2010-07-23 14 views
9

Ho un'applicazione che utilizza Quartz Scheduler per pianificare i lavori. L'applicazione è attualmente in esecuzione Quartz versione 1.6.2. My JobStore è org.quartz.impl.jdbcjobstore.JobStoreTX con un database Oracle che lo supporta. Il clustering è attivo, ma esiste un solo scheduler che utilizza il database. Il mio threadpool Quartz è configurato come segue:Posso far accendere i lavori di Quartz nell'ordine in cui sono stati attivati?

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

I miei lavori sono lunghi in esecuzione, quindi è abbastanza comune avere 5 lavori in esecuzione (il massimo consentito dalla mia piscina thead) quando trigger fuoco nuovi posti di lavoro. I nuovi posti di lavoro innescati cilecca e vedo registrare i messaggi come il seguente:

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. 

Una volta che un processo in esecuzione termina, uno dei lavori cilecca sarà ottenere raccolti e funzionare normalmente. Tuttavia, Quartz sembra raccogliere un lavoro a caso in modo casuale, senza riguardo all'ordine in cui i lavori erano stati originariamente pianificati per l'esecuzione. Idealmente, mi piacerebbe che venissero raccolti nell'ordine in cui avrebbero dovuto correre, in base ai loro tempi di fuoco originali.

È possibile attivare i processi di attesa (non elaborati) nell'ordine in cui sono stati attivati ​​dopo che lo spazio nel Quartz ThreadPool è diventato disponibile?

risposta

2

Quando il quarzo gestisce un trigger che ha mancato il tempo di attivazione, aggiornerà lo nextFireTime del trigger. Per impostazione predefinita, un trigger verrà considerato mancante se è prossimoFireTime è più di 60 secondi nel passato. I trigger mancanti dovrebbero ancora essere selezionati in base al prossimo ordine di tempo e ordine di priorità, ma suppongo che sia casuale perché alcuni trigger sono stati aggiornati e altri no.

Suggerirei di aumentare la proprietà org.quartz.jobStore.misfireThreshold. Vedere http://www.quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigRAMJobStore.html (sebbene la proprietà sia identica per tutti i JobStore). Ciò dovrebbe rendere meno probabile la re-pianificazione dei trigger.

+0

Non riesco davvero a testarlo perché ho un nuovo lavoro, non ho usato il quarzo da anni e non posso essere preso la briga di creare un progetto di test solo per vedere se funziona. Tuttavia, sono impressionato dal fatto che ti sei preso la briga di rispondere a una domanda di 5 anni e la tua risposta sembra utile, quindi vado avanti e segna questo come risolto :) –

+0

Avevo un problema simile, quindi la ricerca stack overflow. Alla fine ho scavato nel codice e ho capito da solo ma ho pensato di lasciarlo qui nel caso in cui qualcun altro stesse cercando la risposta in futuro. – samblake

+0

@JonQuarfoth Cosa ha funzionato per te alla fine? Sto pianificando decine di migliaia di lavori e il lavoro sarà lungo poiché ho bisogno di migrare blob da un luogo all'altro e questi blob possono arrivare a 100 GB. Sto pianificando di usare il clustering del quarzo in modo che quando il master pianifica il lavoro, gli schiavi continueranno a lavorare su quei lavori e non mi interessa davvero il miss fire poiché mi interessa solo che il lavoro venga scelto da uno degli schiavi alla fine . Forse posso impostare un valore soglia di svarione ridicolmente grande. Per favore fatemi sapere cosa ne pensate voi ragazzi. Grazie. – Coder

0

Guardando il quarzo thread pool, utilizza un ciclo wait()/notify(), che non è corretto, e selezionerà casualmente un nuovo thread quando più thread sono in attesa.

È possibile utilizzare la propria istanza di ThreadPool che è corretta. Copia il codice da SimpleThreadPool, ma sostituisci il blocco attorno a nextRunnableLock con un java.util.ReentrantLock, passando true al costruttore fair. Nel tuo SimpleThreadPool modificato, usa ReentrantLock.lock()/unlock() invece di sincronizzato, e usa ReentrantLock.newCondition(). Signal()/await() invece di wait/notify, e potrebbe risolvere il tuo problema.

+0

Questi thread nel pool non hanno lavori assegnati a loro, quindi l'equità di cui si parla non ha importanza. Qualunque di questi thread venga prima gratuito, eseguirà il prossimo lavoro. – jhouse

+0

Penso che l'equità provenga da thread esterni al pool di thread, runInThread e blockForAvailableThreads aspettano entrambi ingiustamente. Cosa intendevi quando hai detto "quando il mio pool di thread è al massimo" – sbridges

+0

runInThread() e blockForAvailableThreads() sono entrambi chiamati dallo stesso thread - non ci sono più thread in attesa del risultato di questi metodi, quindi 'equità' di wait()/notify() non importa. (Solo un servizio thread/utilizza il pool di thread). – jhouse

2

Sembra che tu stia correndo in uno scenario non corretto (uno scenario in cui ci sono più lavori pronti per essere eseguiti rispetto a quelli di lavoro). Imposta l'istruzione misfire e/o la proprietà priority sui trigger per modificare il modo in cui ciascuno si comporta dopo aver superato il tempo di attivazione.

Inoltre, si potrebbe prendere in considerazione l'aumento della soglia di mancato spegnimento, che cambierebbe la quantità di tempo in cui un trigger può essere "tardivo" in attesa dell'esecuzione di un thread prima che venga considerato un errore di attivazione (e viene applicata la relativa istruzione di mancata accensione).

È possibile far sparire i lavori in attesa (non elaborati) nell'ordine in cui sono stati attivati ​​dopo che lo spazio nel Quartz ThreadPool diventa disponibile?

Le istruzioni "non fare nulla" lasceranno i tempi del fuoco così come sono.

+0

È sicuramente uno scenario di svuotamento: ho aggiornato la domanda per essere un po 'più specifica su questo punto. Esiste un'istruzione sbagliata che farebbe ritirare i lavori falliti nell'ordine in cui sono stati originariamente licenziati? –

+3

Il javadoc per la mancata accensione MISFIRE_INSTRUCTION_DO_NOTHING si legge come segue: "Indica all'utilità di pianificazione che in caso di situazione anomala, CronTrigger desidera che il suo prossimo tempo di accensione venga aggiornato alla volta successiva nella pianificazione dopo l'ora corrente, ma lo fa non voglio essere licenziato ora. " Forse ho frainteso, ma a me sembra che il lavoro salti il ​​tiro e non faccia nulla fino alla prossima volta che viene attivato. Questo non è quello che voglio. Voglio che il lavoro venga eseguito non appena ci sono thread disponibili, ma con i lavori con l'attesa più lunga che vengono eseguiti per primi se ci sono più lavori falliti. –

0

In caso di un , il metodo updateAfterMisfire() può riprogrammare l'attività in new Date() criterio MISFIRE_INSTRUCTION_FIRE_ONCE_NOW.

Se diverse attività sono errate, molte di esse possono essere riprogrammate contemporaneamente (stesso millisecondo), perché il computer funziona velocemente.

Di conseguenza, e se nessuna priorità è definita, lo scheduler preleverà il primo compito successivo, il tutto con lo stesso NextFireTime, in base alla chiave o al nome completo.

updateAfterMisfire() metodo dovrebbe avere riprogrammare l'attività a un date univoco utilizzando un Thread.sleep(25), ad esempio.

Problemi correlati