48 votes

Assurez-vous que l'exécution du travail Spring Quartz ne se chevauche pas

J'ai un programme Java qui s'exécute à partir de Spring Qquartz toutes les 20 secondes. Parfois, l'exécution ne prend que quelques secondes, mais à mesure que les données deviennent plus volumineuses, je suis sûr qu'elles durent 20 secondes ou plus.

Comment puis-je empêcher Quartz de déclencher / déclencher le travail alors qu'une instance est encore en cours d'exécution? L'activation de deux tâches exécutant les mêmes opérations sur une base de données ne serait pas très utile. Est-ce qu'il y a un moyen de faire une sorte de synchronisation?

Je vous remercie

144voto

Dónal Points 61837

Quartz 1

Si vous changez de classe pour mettre en œuvre StatefulJob au lieu de Travail, de Quartz prendra soin de cela pour vous. À partir de la StatefulJob javadoc:

dynamique des emplois ne sont pas autorisés à exécuter simultanément, ce qui signifie de nouveaux les déclencheurs qui se produisent avant l' l'achèvement de l'exécution(xx) méthode sera retardé.

StatefulJob s'étend de l'Emploi et de ne pas ajouter de nouvelles méthodes, de sorte que vous devez faire pour obtenir le comportement que vous voulez est de changer ce:

public class YourJob implements org.quartz.Job {
    void execute(JobExecutionContext context) {/*implementation omitted*/}
}

Pour cela:

public class YourJob implements org.quartz.StatefulJob {
    void execute(JobExecutionContext context) {/*implementation omitted*/}
}

Quartz 2

Dans la version 2.0 de Quartz, StatefulJob est obsolète. Il est maintenant recommandé d'utiliser des annotations au lieu de cela, par exemple

@DisallowConcurrentExecution
public class YourJob implements org.quartz.Job {
    void execute(JobExecutionContext context) {/*implementation omitted*/}
}

31voto

skaffman Points 197885

Si tout ce que vous devez faire est de tirer toutes les 20 secondes, le Quartz est sérieux exagéré. L' java.util.concurrent.ScheduledExecutorService devrait être tout à fait suffisante pour ce travail.

L' ScheduledExecutorService fournit également deux sémantique pour la planification. "taux fixe" tentera d'exécuter votre travail toutes les 20 secondes, indépendamment de la superposition, alors que le "délai" va tenter de laisser 20 secondes entre la fin de la première tâche et le début de la prochaine. Si vous voulez éviter les chevauchements, puis fixe le retard est le plus sûr.

19voto

gshauger Points 526

Juste au cas où quelqu'un fait référence à cette question, StatefulJob a été désapprouvée. Maintenant, ils vous suggérons d'utiliser les annotations à la place...

@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class TestJob implements Job {

Cela permettra d'expliquer ce que ces annotations veux dire...

Les annotations cause comportement, tout comme leurs noms décrivent - plusieurs les instances de la tâche ne sera pas autorisé à s'exécuter simultanément (pensez à un cas où un travail a code dans sa la méthode execute() qui prend 34 secondes pour l'exécuter, mais il est programmé avec une trigger qui se répète toutes les 30 secondes), et aura son JobDataMap contenu re-persisté dans l' planificateur de JobStore après chaque l'exécution. Pour les fins de la présente exemple, seulement @PersistJobDataAfterExecution l'annotation est vraiment pertinente, mais c'est toujours sage d'utiliser le @DisallowConcurrentExecution annotation avec elle, pour éviter course à conditions sur les données enregistrées.

4voto

Paul Points 12

si vous utilisez du quartz à ressort, je pense que vous devez configurer comme ceci

     <bean id="batchConsumerJob"class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="myScheduler" />
        <property name="targetMethod" value="execute" />
        <property name="concurrent" value="false" />
    </bean>
 

2voto

Brian Agnew Points 143181

Je ne suis pas sûr que vous voulez de synchronisation, depuis la seconde tâche sera bloqué jusqu'à ce que la première est terminée, et vous vous retrouverez avec un carnet de commandes. Vous pourriez mettre les emplois dans une file d'attente, mais à partir de votre description, il semble que la file d'attente peut croître indéfiniment.

Je voudrais étudier ReadWriteLocks, et laissez votre tâche de définir un verrouillage, alors qu'il est en cours d'exécution. Les tâches futures peuvent inspecter ce verrou, et de quitter immédiatement si une mission est toujours en cours d'exécution. J'ai trouvé par expérience que c'est le moyen le plus fiable de cette approche.

Peut-être générer un avertissement en tant que bien de sorte que vous savez que vous avez rencontrer des problèmes et d'augmenter l'intervalle de temps en conséquence ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X