2010-07-23 17 views
9

Ich habe eine Anwendung mit dem Quartz Scheduler, um Jobs zu planen. Die Anwendung führt derzeit die Quartz-Version 1.6.2 aus. Mein JobStore ist org.quartz.impl.jdbcjobstore.JobStoreTX mit einer Oracle-Datenbank, die dies unterstützt. Clustering ist aktiviert, aber es gibt nur einen Scheduler, der die Datenbank verwendet. Mein Quartz Threadpool wird wie folgt konfiguriert:Kann ich warten, dass Quartz Jobs in der Reihenfolge ausgelöst werden, in der sie ausgelöst wurden?

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool 
org.quartz.threadPool.threadCount = 5 
org.quartz.threadPool.threadPriority = 5 

Meine Jobs sind langer Lauf, also ist es ziemlich häufig 5 Arbeitsplätze zu laufen hat (das Maximum von meinem Thead Pool erlaubt), wenn Trigger neue Arbeitsplätze feuert. Die neu ausgelöst Jobs Fehlzündungen und ich sehe, Log-Meldungen wie folgt aus:

2011-05-20 04:09:30,097 INFO [QuartzScheduler_scheduler-servername-111305822374881_MisfireHandler] o.q.p.h.LoggingTriggerHistoryPlugin - Trigger DEFAULT.JobName1 misfired job DEFAULT.DEFAULT at: 04:09:30 05/20/2011. Should have fired at: 04:08:29 05/20/2011 
2011-05-20 04:09:30,120 INFO [QuartzScheduler_scheduler-servername-111305822374881_MisfireHandler] o.q.p.h.LoggingTriggerHistoryPlugin - Trigger DEFAULT.JobName1 misfired job DEFAULT.DEFAULT at: 04:09:30 05/20/2011. Should have fired at: 04:09:30 05/20/2011 
2011-05-20 04:09:30,125 INFO [QuartzScheduler_scheduler-servername-111305822374881_MisfireHandler] o.q.p.h.LoggingTriggerHistoryPlugin - Trigger DEFAULT.JobName2 misfired job DEFAULT.DEFAULT at: 04:09:30 05/20/2011. Should have fired at: 04:08:30 05/20/2011 
2011-05-20 04:09:30,138 INFO [QuartzScheduler_scheduler-servername-111305822374881_MisfireHandler] o.q.p.h.LoggingTriggerHistoryPlugin - Trigger DEFAULT.JobName2 misfired job DEFAULT.DEFAULT at: 04:09:30 05/20/2011. Should have fired at: 04:09:30 05/20/2011 
2011-05-20 04:11:29,998 INFO [QuartzScheduler_scheduler-servername-111305822376676_MisfireHandler] o.q.impl.jdbcjobstore.JobStoreTX - Handling 2 trigger(s) that missed their scheduled fire-time. 

Sobald ein laufender Job beendet, einer der fehl zündenden Arbeitsplätze werden abgeholt und normal laufen. Quartz scheint jedoch zufällig einen fehlgesteuerten Auftrag aufzunehmen, ohne die Reihenfolge zu berücksichtigen, in der die Aufträge ursprünglich ausgeführt wurden. Idealerweise hätte ich gerne, dass sie in der Reihenfolge abgeholt werden, in der sie ausgeführt werden sollten, basierend auf ihren ursprünglichen Feuerzeiten.

Ist es möglich, dass meine wartenden (fehlgesteuerten) Jobs in der Reihenfolge ausgelöst werden, in der sie ausgelöst wurden, sobald Speicherplatz im Quartz ThreadPool verfügbar wird?

Antwort

2

Wenn Quarz einen Auslöser behandelt, der seine Feuerzeit verpasst hat, aktualisiert er den nextFireTime des Auslösers. Standardmäßig wird ein Trigger als verpasst betrachtet, wenn nextFireTime in der Vergangenheit länger als 60 Sekunden ist. Verpasste Trigger sollten immer noch basierend auf nextFireTime und Prioritätsreihenfolge ausgewählt werden, aber ich vermute, dass es zufällig erscheint, weil einige Trigger aktualisiert wurden und andere nicht.

Ich würde vorschlagen, die org.quartz.jobStore.misfireThreshold Eigenschaft zu erhöhen. Siehe http://www.quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigRAMJobStore.html (obwohl die Eigenschaft für alle JobStores identisch ist). Dies sollte es weniger wahrscheinlich machen, dass Ihre Trigger neu geplant werden.

+0

Ich kann das nicht wirklich testen, weil ich einen neuen Job bekommen habe, seit Jahren keinen Quarz mehr benutzt habe und nicht daran interessiert bin, ein Testprojekt zu starten, nur um zu sehen, ob das funktioniert. Wie auch immer, ich bin beeindruckt, dass Sie sich die Mühe gemacht haben, eine 5 Jahre alte Frage zu beantworten, und Ihre Antwort scheint hilfreich zu sein, also werde ich das als gelöst markieren :) –

+0

Ich hatte ein ähnliches Problem, also suchte ich Paketüberfluss. Am Ende durchforstete ich den Code und fand es selbst heraus, dachte aber, ich würde das hier lassen, für den Fall, dass jemand in Zukunft nach der Antwort suchen würde. – samblake

+0

@JonQuarfoth Was hat am Ende für dich funktioniert? Ich plane 10s Tausende von Job und Job wird lange dauern, wie ich Blob von Ort zu einem anderen migrieren muss und diese Blobs können so groß wie 100 GB sein. Ich plane, Quartz-Clustering zu verwenden, so dass, wenn der Master den Job plant, Sklaven an diesen Jobs weiterarbeiten werden und ich mich nicht wirklich um Fehlzündungen kümmere, da ich mich nur darum kümmere, dass der Job am Ende von einem der Sklaven abgeholt wird . Vielleicht kann ich einen lächerlich großen Fehlzündungsschwellwert setzen. Bitte lass mich wissen, was ihr darüber denkt. Vielen Dank. – Coder

0

Mit Blick auf die Quarz thread pool, verwendet es eine wait()/notify() - Schleife, die nicht fair ist, und wird zufällig einen neuen Thread auswählen, wenn mehrere Threads warten.

Sie könnten Ihre eigene Instanz von ThreadPool verwenden, die fair ist. Kopieren Sie den Code aus SimpleThreadPool, aber ersetzen Sie das Locking um nextRunnableLock durch java.util.ReentrantLock und übergeben Sie den Fair-Konstruktor. Verwenden Sie in Ihrem modifizierten SimpleThreadPool ReentrantLock.lock()/unlock() statt synchronisiert und verwenden Sie ReentrantLock.newCondition(). Signal()/await() statt warten/notify, und es könnte Ihr Problem lösen.

+0

Diesen Threads im Pool sind keine Jobs zugewiesen, daher spielt die Fairness, über die Sie sprechen, keine Rolle. Welcher dieser Threads zuerst frei wird, wird den nächsten Job ausführen. – jhouse

+0

Ich glaube, die Fairness kommt von Threads außerhalb des Threadpools, runInThread und blockForAvailableThreads warten beide unfair. Was meintest du damit, als du sagst: "Wenn mein Thread-Pool ausgereizt ist" – sbridges

+0

runInThread() und blockForAvailableThreads() werden beide aus demselben Thread aufgerufen - es warten nicht mehrere Threads auf das Ergebnis dieser Methoden, also 'Fairness' von wait()/notify() spielt keine Rolle. (Nur ein Thread bedient/verwendet den Thread-Pool). – jhouse

2

Ich höre, dass Sie in ein fehlzündendes Szenario geraten (ein Szenario, in dem mehr Jobs zur Ausführung bereitstehen als es Worker-Threads gibt). Legen Sie die Fehlzündungsanweisung und/oder die Prioritätseigenschaft für die Trigger fest, um zu ändern, wie sich jedes Verhalten nach Ablauf der Feuerzeit verhält.

Sie könnten auch erwägen, den Fehlzündungsschwellenwert zu erhöhen, wodurch sich die Zeitspanne ändern würde, in der ein Trigger "spät" darauf wartet, dass ein Thread ausgeführt wird, bevor er als Fehlzündung betrachtet wird).

Ist es möglich, dass meine wartenden (fehlgesteuerten) Jobs in der Reihenfolge ausgelöst werden, in der sie ausgelöst wurden, sobald Speicherplatz im Quartz ThreadPool verfügbar wird?

Die "nichts tun" -Anweisungen werden das Feuer so wie es ist verlassen.

+0

Es ist definitiv ein Fehlzündungsszenario - ich habe die Frage aktualisiert, um in diesem Punkt etwas genauer zu sein. Gibt es eine Fehlzündungsanweisung, die dazu führt, dass die fehlgeschlagenen Aufträge in der Reihenfolge abgerufen werden, in der sie ursprünglich ausgelöst wurden? –

+3

Das Javadoc für die Fehlzündung MISFIRE_INSTRUCTION_DO_NOTHING lautet wie folgt: "Weist den Scheduler an, dass der CronTrigger bei einer Fehlzündungssituation die nächste Feuerzeit auf das nächste Mal im Zeitplan nach der aktuellen Zeit aktualisieren möchte, aber dies tut er Ich möchte jetzt nicht gefeuert werden. " Vielleicht verstehe ich das falsch, aber das hört sich für mich so an, als würde der Job nur das Feuern überspringen und nichts tun, bis es das nächste Mal ausgelöst wird. Das ist nicht was ich will. Ich möchte, dass der Job ausgeführt wird, sobald Threads verfügbar sind. Die Jobs mit den längsten Wartezeiten werden jedoch zuerst ausgeführt, wenn mehrere fehlgeschlagene Jobs vorhanden sind. –

0

Im Falle eines CronTrigger, wobei das Verfahren updateAfterMisfire() kann die Aufgabe bei new Date() Fall MISFIRE_INSTRUCTION_FIRE_ONCE_NOW Politik neu planen.

Wenn mehrere Tasks fehlgeschlagen sind, können einige von ihnen zur gleichen Zeit (in der gleichen Millisekunde) neu geplant werden, da der Computer schnell läuft.

Als Konsequenz, und wenn keine Priorität definiert ist, wird der Scheduler die erste nächste Aufgabe übernehmen, alle mit demselben NextFireTime, je nach Schlüssel oder vollständigen Namen.

updateAfterMisfire() Methode sollte die Aufgabe zu einem eindeutigen date mit einem Thread.sleep(25) als Beispiel umprogrammieren.

Verwandte Themen