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?

21
demandé sur Savvas Dalkitsis 2009-12-19 21:02:22

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;
    }
}
28
répondu Eduard Wirch 2016-04-21 16:32:19

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.

5
répondu skaffman 2009-12-19 18:05:43

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.

1
répondu Michael Deardeuff 2010-02-14 05:36:09