Quartz Java reprendre un travail l'excécute plusieurs fois
pour mon application je crée des emplois et les planifie avec CronTriggers. Chaque emploi n'a qu'un seul déclencheur et le nom de l'emploi et le nom du déclencheur sont les mêmes. Pas d'emplois de partager un déclencheur.
maintenant quand je crée un déclencheur cron comme ceci "0/1 * * * * ?" qui demande au travail d'exécuter chaque seconde, ça marche très bien.
le problème surgit lorsque j'interromps le travail pour la première fois en appelant :
scheduler.pauseJob(jobName, jobGroup);
et de reprendre le travail après disons 50 secondes avec :
scheduler.resumeJob(jobName, jobGroup);
ce que je vois c'est que pendant ces 50 secondes le travail n'a pas fonctionné comme demandé. Mais au moment où je reprends le travail, je vois 50 exécutions de la tâche en même temps!!!
j'ai pensé que cela était dû au réglage par défaut de l'instruction misfire mais même après avoir réglé l'instruction misfire du trigger sur la création à ceci :
trigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);
la même chose se produit. Quelqu'un peut-il suggérer un moyen de réparer ça?
3 réponses
CronTrigger
fonctionne en se souvenant de l' nextFireTime
. Après avoir créé le déclencheur le nextFireTime
est initialisé. Chaque fois que le travail est déclenché nextFireTime
est mis à jour. Depuis le travail n'est pas déclenché lorsque la pause nextFireTime
reste "vieux". Donc après avoir repris le travail, la gâchette reviendra à chaque fois.
Le problème est que le déclencheur ne sait pas qu'elle est en pause. Pour surmonter cela, il y a cette manipulation erronée. Après avoir repris les travaux, le déclencheur est updateAfterMisfire()
méthode être invoquée qui corrige l' nextFireTime
. Mais pas si la différence entre nextFireTime
et maintenant, c'est plus petit que le misfireThreshold. Ensuite, la méthode n'est jamais appelée. La valeur par défaut de ce seuil est de 60 000. Ainsi, si votre période de suspension serait de plus de 60, tout irait bien.
puisque vous avez des problèmes, je suppose que ce n'est pas le cas. ;)
Pour contourner cela, vous pouvez modifier le seuil ou utiliser un simple wrapper autour de CronTrigger
:
public class PauseAwareCronTrigger extends CronTrigger {
// constructors you need go here
@Override
public Date getNextFireTime() {
Date nextFireTime = super.getNextFireTime();
if (nextFireTime.getTime() < System.currentTimeMillis()) {
// next fire time after now
nextFireTime = super.getFireTimeAfter(null);
super.setNextFireTime(nextFireTime);
}
return nextFireTime;
}
}
si vous interrompez le travail, le déclencheur continuera de s'allumer, mais les exécutions feront la queue jusqu'à ce que le travail reprenne. Ce n'est pas une gâchette ratée, donc ce réglage n'aura aucun effet.
ce que vous voulez faire, je pense, c'est désactiver programmatiquement ou supprimer le déclencheur cron, plutôt que d'interrompre le travail. Lorsque vous voulez reprendre, puis Ajouter à nouveau la gâchette.
depuis 1.6.5 au moins (la version la plus ancienne de quartz à portée de main), le scheduler a une méthode pauseTrigger qui prend le nom/groupe comme paramètres. Cela signifie que vous ne devez pas avoir une sous-classe de chaque type de gâchette que vous utilisez, ni vous avez à faire funky suppression/insertion trucs.
les deux sont importants pour moi parce que 1) notre base de données a une politique stricte de non-suppression et 2) le datastore personnalisé que j'utilise ne supporte pas les sous-classes de déclenchement.