2009-12-19 5 views
21

Für meine Anwendung erstelle ich Jobs und plane sie mit CronTriggers. Jeder Job hat nur einen Trigger und sowohl der Name des Jobs als auch der Name des Triggers sind identisch. Keine Jobs teilen einen Trigger.Quartz Java, das einen Job wieder aufnimmt, übertrifft es oft

Jetzt, wenn ich einen Cron-Trigger wie diese erstellen "0/1 * * * *?", die den Auftrag anweist, jede Sekunde auszuführen, funktioniert es gut.

Das Problem steigt, wenn ich zum ersten Mal den Job Pause durch den Aufruf:

scheduler.pauseJob(jobName, jobGroup); 

und dann den Job wieder aufzunehmen, nachdem die mit 50 Sekunden lassen sagen:

scheduler.resumeJob(jobName, jobGroup); 

Was ich sehe, ist, dass für diese 50 Sekunden wurde der Auftrag nicht wie gewünscht ausgeführt. Aber in dem Moment, in dem ich den Job wieder beginne, sehe ich 50 Ausführungen des Jobs zur gleichen Zeit !!!

Ich dachte, dass dies aufgrund der Standardeinstellung für die Fehlzündung Anweisung war aber auch nach dem Abzug der Fehlzündung instruciton bei der Erstellung dieser Einstellung:

trigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING); 

Das gleiche geschieht. Kann jemand vorschlagen, das zu beheben?

Antwort

27

Die CronTrigger funktioniert durch die Erinnerung an die nextFireTime. Nach dem Erstellen des Triggers wird nextFireTime initialisiert. Jedes Mal, wenn der Job ausgelöst wird, wird nextFireTime aktualisiert. Da der Auftrag bei Pausierung nicht ausgelöst wird, bleibt nextFireTime "alt". Nachdem Sie den Job wieder aufgenommen haben, gibt der Trigger jede alte Triggerzeit zurück.

Das Problem ist, der Trigger weiß nicht, dass es pausiert wird. Um dies zu vermeiden, gibt es diese Fehlzündungsbehandlung. Nach dem Fortsetzen der Jobs wird die Methode updateAfterMisfire() des Triggers aufgerufen, die die nextFireTime korrigiert. Aber nicht, wenn der Unterschied zwischen nextFireTime und jetzt kleiner ist als der misfireThreshold. Dann wird die Methode nie aufgerufen. Der Standardwert dieses Schwellenwerts ist 60.000. Wenn also Ihre Pause länger als 60 ist, wäre alles in Ordnung.

Da Sie Probleme haben, nehme ich an, dass es nicht ist. ;) Um dies zu umgehen können Sie den Schwellenwert ändern oder einen einfachen Wrapper um CronTrigger verwenden:

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; 
    } 
} 
+4

Danke sooo viel :) das hat wie ein Zauber funktioniert. Es erscheint merkwürdig, dass so eine einfache Aufgabe wie das Pausieren eines Jobs Probleme wie diese verursacht. –

5

Wenn Sie den Job pausieren, wird der Trigger weiterhin ausgelöst, aber die Ausführungen werden anstehen, bis der Job wieder aufgenommen wird. Dies ist kein Fehlzündungsauslöser, so dass die Einstellung keine Auswirkungen hat.

Was Sie tun möchten, ist, denke ich, ist programmgesteuert deaktivieren oder entfernen Sie den Cron-Trigger, anstatt den Job zu pausieren. Wenn Sie fortfahren möchten, fügen Sie den Trigger erneut hinzu.

+0

Das Javadoc für die pauseJob-Methode sagt "Pausieren Sie den JobDetail mit dem angegebenen Namen - indem Sie alle seine aktuellen Trigger pausieren." also vermute ich, dass der Trigger pausiert wird. Es gibt auch keine Pause-Methode für den Trigger selbst. Oder irgendetwas, das ihm ähnelt. Einfach den Trigger aus dem Job entfernen und ihn wieder einfügen, meine einzige Option, einen Job anzuhalten? Ich meine, das ist eine ziemlich triviale Sache, die Ihr Scheduler machen soll. Wie kommt es, dass es nicht einfach funktioniert? –

+0

Hmm, guter Punkt. Ich finde, dass mit Quartz verschiedene Dinge auszuprobieren, bis etwas funktioniert, ist der produktivste Ansatz, da es nicht immer das tut, was es auf der Dose sagt. – skaffman

+0

Dies ist extrem frustrierend, da es auch keinen einfachen Weg gibt, einen Trigger einfach aus dem Job zu entfernen. Kann ich einen auslöserlosen Job haben? und wenn ja, wie? Irgendwelche Ideen? Ich fange an, meine Geduld damit zu verlieren, ich habe es stundenlang versucht :) –

1

Da 1.6.5 mindestens (die früheste Version von Quarz an den Fingerspitzen), der Scheduler eine pauseTrigger Methode verfügt, die Nimmt den Namen/die Gruppe als Parameter. Das bedeutet, dass Sie keine Unterklasse für jeden verwendeten Triggertyp haben müssen und auch keine funky Lösch-/Einfüge-Tricks machen müssen.

Beide sind wichtig für mich, weil 1) unsere Datenbank eine strikte No-Deletes-Richtlinie hat und 2) der benutzerdefinierte Datenspeicher, den ich verwende, Trigger-Unterklassen nicht unterstützt.