2015-05-18 5 views
7

Ich versuche, eine Aufgabe mit einer festen Rate auszuführen, indem ich die @Scheduled-Annotation in der Java-Quelle verwende. Es scheint jedoch, dass Spring standardmäßig keine festeRate-Aufgabe mit einer festen Rate ausführt, wenn die Aufgabe langsamer als die Rate ist. Gibt es eine Einstellung, die ich zu meiner Federkonfiguration hinzufügen kann, um dieses Verhalten zu ändern?Wie können Sie Spring so konfigurieren, dass überlappende FixedRate-Tasks ausgeführt werden?

Beispiel:

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

ich habe eine Behelfslösung, aber es scheint, weniger als ideal. im Grunde genommen, ich ersetzen Sie einfach den Standard-Single-Thread-Vollstrecker mit einem Thread-Pool, dann habe ich ein geplantes Verfahren zur Herstellung eines Asynchron-Methode aufrufen, da die @Async Annotation parallele Ausführung ermöglicht:

@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); 
    } 
} 

langweiligen Details meiner realen Welt Szenario: In meinem Produktionscode habe ich eine Aufgabe, die abhängig von der aktuellen Auslastung zwischen 10ms und 10 Minuten dauert. Idealerweise möchte ich alle 1000ms einen neuen Thread aus dem Pool erfassen, sodass die Anzahl der gleichzeitigen Threads mit der Arbeitslast zunimmt. Natürlich habe ich eine Obergrenze für Threads (neben anderen Kontrollen), um zu verhindern, dass die Dinge außer Kontrolle geraten.

Antwort

3

Die TaskScheduler API (die ein Teil des Feder Scheduling Verhalten sichert) definiert zu sein scheint, das Verhalten zu verhindern, dass Sie

fordern

Planen Sie den gegebenen Runnable, es an der angegebenen Ausführung Zeit aufrufen und anschließend mit der angegebene Zeitraum.

Parameter

  • Zeitraum das Intervall zwischen aufeinanderfolgenden Ausführungen der Aufgabe (in Millisekunden)

anschließend und sukzessive scheint anzuzeigen, dass die nächste Ausführung wird nur auftreten, nachdem die aktuelle Ausführung abgeschlossen ist.

Was mehr ist, ScheduledExecutorService#scheduleAtFixedRate(..) (das ist der eingebaute in TaskScheduler Implementierungen verwenden) sagt auch

Wenn eine Ausführung dieser Aufgabe länger als seine Zeit dauert, dann nachfolgenden Ausführungen, spät beginnen kann aber nicht gleichzeitig ausführen.

Es gibt also eine andere Ebene der Implementierung, die das gewünschte Verhalten verhindert.

Eine mögliche Lösung, und eine, die ich nicht empfehlen, da die API scheint nicht um es herum gebaut werden, ist zu definieren und bieten Sie Ihre eigenen TaskScheduler, die die Aufgabe gleichzeitig ausgeführt wird. Sehen Sie in @EnableScheduling und SchedulingConfigurer nach, wie man einen TaskScheduler anmeldet.

+0

i die Referenzen zu schätzen wissen, und untersuche die SchedulingConfigurer und cron Muster basierte Arbeitsplätze. das sagte, ich stimme nicht mit Ihrer Interpretation von "nachher" und "sukzessive" überein, und möchte eine Lösung (wie peinlich), die mein Ziel erreicht. Daher möchte ich noch etwas länger warten, bevor ich diese Antwort in der Hoffnung akzeptiere, dass jemand mit einer speziellen funktionalen Federkonfiguration aufwarten kann. –

1

Die beste Lösung, die ich bisher gefunden habe, ist einfach einen Delegaten zu verwenden, um die Methode async aufzurufen. dies ist nur bevorzugt, weil es mir erlaubt, den Zeitplan in der gleichen Klasse wie die Methode zu erklären, die die Arbeit macht:

@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 
     ... 
    } 
} 
Verwandte Themen