2015-05-18 13 views
7

Próbuję wykonać zadanie ze stałą stawką za pomocą @ Zaplanowane adnotacji w java wiosny. wydaje się jednak, że domyślnie sprężyna nie wykona zadania fixedRate o stałej szybkości, jeśli zadanie jest wolniejsze niż szybkość. czy jest jakieś ustawienie, które mogę dodać do mojej wiosennej konfiguracji, aby zmienić to zachowanie?Jak skonfigurować sprężynę do wykonywania nakładających się zadań fixedRate?

przykład:

@Service 
public class MyTask{ 
    @Scheduled(fixedRate = 1000) 
    public void doIt(){ 
     // this sometimes takes >1000ms, in which case the next execution is late 
     ... 
    } 
} 

Mam obejście, ale wydaje się mniej niż idealne. Zasadniczo wystarczy zastąpić wykonawcę domyślne jednego wątku z puli wątków, a następnie Mam metodę zaplanowane wywołać metodę transmisji asynchronicznej ponieważ adnotacja @Async umożliwia równoczesne wykonaniach:

@Service 
public class MyTask{ 
    @Async 
    public void doIt(){ 
     // this sometimes takes >1000ms, but the next execution is on time 
     ... 
    } 
} 

@Service 
public class MyTaskScheduler{ 
    ... 
    @Scheduled(fixedRate = 1000) 
    public void doIt(){ 
     myTask.doIt(); 
    } 
} 

@Configuration 
@EnableScheduling 
@EnableAsync 
public class MySpringJavaConfig{ 
    @Bean(destroyMethod = "shutdown") 
    public Executor taskScheduler() { 
     return Executors.newScheduledThreadPool(5); 
    } 
} 

nudne szczegóły mojego świecie rzeczywistym scenariusz: w moim kodzie produkcyjnym mam zadanie, które trwa od 10ms do 10 minut, w zależności od bieżącego obciążenia. Idealnie, chciałbym przechwycić nowy wątek z puli co 1000ms, tak aby liczba współbieżnych wątków wzrastała wraz z obciążeniem. oczywiście mam górny limit nici w miejscu (między innymi kontrolami), aby nie wymknąć się spod kontroli.

Odpowiedz

3

TaskScheduler API (który popiera niektóre z zachowań Planowanie Wiosna) wydaje się być zdefiniowane, aby zapobiec zachowanie żądasz

Harmonogram dany Runnable, powołując go w określonym wykonanie raz, a następnie z podany okres.

Parametry

  • okres odstęp pomiędzy kolejnymi egzekucjami zadania (w milisekundach)

następnie i kolejny wydają się wskazywać, że następne wykonanie nastąpi dopiero po zakończeniu bieżącej realizacji.

Co więcej, ScheduledExecutorService#scheduleAtFixedRate(..) (który wbudowany TaskScheduler wdrożeń używać) również mówi

Jeżeli którykolwiek wykonanie tego zadania trwa dłużej niż okres, a następnie kolejne egzekucje mogą rozpocząć późno, ale nie będzie jednocześnie wykonać.

Istnieje więc kolejna warstwa implementacji, która uniemożliwia zachowanie, które chcesz.

Możliwym rozwiązaniem, którego nie polecam, ponieważ API nie jest zbudowany wokół niego, jest zdefiniowanie i dostarczenie własnego TaskScheduler, który uruchamia zadanie równolegle. Zajrzyj do @EnableScheduling i SchedulingConfigurer, aby dowiedzieć się, jak zarejestrować numer TaskScheduler.

+0

Doceniam referencje, i jestem bada SchedulingConfigurer i cron wzór oparty pracy. to powiedziawszy, nie zgadzam się z twoją interpretacją "kolejno" i "sukcesywnie", i chciałbym rozwiązania (jakkolwiek niezręcznego), które spełni mój cel. jako takie, mam zamiar poczekać trochę dłużej, zanim przyjmiemy tę odpowiedź w nadziei, że ktoś może wymyślić konkretną funkcjonalną konfigurację sprężyny. –

1

najlepszym rozwiązaniem, jakie dotychczas znalazłem, jest po prostu użycie delegata, aby wywołać metodę asynchroniczną. to tylko korzystne, ponieważ pozwala mi na stwierdzenie, że rozkład w tej samej klasie jako metodę, która wykonuje pracę:

@Service 
public class AsyncRunner { 
    @Async 
    public void run(Runnable runnable) { 
     runnable.run(); 
    } 
} 

@Service 
public class MyTask{ 
    ... 
    @Scheduled(fixedRate = 1000) 
    public void scheduleIt(){ 
     asyncRunner.run(this::doIt); 
    } 
    public void doIt(){ 
     // this sometimes takes >1000ms, but the next execution is on time 
     ... 
    } 
} 
Powiązane problemy