2010-07-23 66 views
9

我有一個應用程序使用Quartz Scheduler來安排作業。該應用程序當前正在運行Quartz版本1.6.2。我的JobStore是org.quartz.impl.jdbcjobstore.JobStoreTX以及支持它的Oracle數據庫。集羣已打開,但只有一個使用數據庫的調度程序。我石英線程池的配置如下:我可以讓等待Quartz Jobs按照它們被觸發的順序觸發嗎?

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

我的工作是長時間運行,所以它是相當常見的有5個作業運行(由我THEAD池所允許的最大值)時,觸發器觸發新的就業機會。新觸發工作失火,我看到日誌消息如下所示:

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. 

一旦運行作業完成,在該失火的工作之一將得到回升和正常運行。但是,Quartz似乎隨機挑選了一個失誤的工作,而不考慮工作原定執行的順序。理想情況下,我希望他們根據他們原來的火災時間按照他們原本應該運行的順序進行拾取。

一旦Quartz ThreadPool中的空間變得可用,是否有可能使我的等待(失火)作業按照它們被觸發的順序被觸發?

回答

2

當石英處理錯過觸發時間的觸發器時,它將更新觸發器的nextFireTime。默認情況下,如果過去的nextFireTime超過60秒,觸發器將被視爲錯過。仍然應該根據nextFireTime和優先級順序選擇錯過的觸發器,但我猜測它似乎是隨機的,因爲一些觸發器已被更新,而其他觸發器沒有更新。

我會建議增加org.quartz.jobStore.misfireThreshold屬性。請參閱http://www.quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigRAMJobStore.html(儘管該屬性對於所有JobStore都是相同的)。這應該會使您的觸發器重新排定的可能性降低。

+0

我無法真正地測試這個,因爲我找到了一份新工作,多年沒有使用過石英,並且無法設置測試項目來檢查它是否有效。不過,我留下了深刻的印象,你已經很難回答一個5年的問題,你的答案似乎有幫助,所以我會繼續前進,並將其標記爲已解決:) – 2016-04-22 15:39:30

+0

我遇到了類似的問題,所以搜索堆棧溢出。最後,我通過代碼挖掘出自己的想法,但認爲我會在這裏留下來,以防其他人在未來尋找答案。 – samblake 2016-04-24 10:41:47

+0

@JonQuarfoth到底什麼對你有用?我安排了成千上萬的工作,工作將會長時間運行,因爲我需要將blob從位置遷移到另一個位置,而這些blob可以大到100GB。我正計劃使用Quartz集羣,以便在主人安排工作時,奴隸將繼續在這些工作上工作,而且我並不在意丟失火,因爲我只關心最終由其中一個奴隸挑選的工作。也許我可以設置一個荒謬的大失火閾值。請讓我知道你們對此有何看法。謝謝。 – Coder 2017-11-21 03:45:34

0

看着石英thread pool,它使用了一個wait()/ notify()循環,這是不公平的,並且會在多線程等待時隨機選擇一個新線程。

你可以使用你自己的ThreadPool實例,這是公平的。從SimpleThreadPool複製代碼,但用java.util.ReentrantLock替換nextRunnableLock周圍的鎖定,將true傳遞給公平構造函數。在您修改的SimpleThreadPool中,使用ReentrantLock.lock()/ unlock()而不是synchronized,並使用ReentrantLock.newCondition()。signal()/ await()而不是wait/notify,它可能會解決您的問題。

+0

池中的那些線程沒有分配給它們的作業,所以你談論的公平性並不重要。無論哪個線程先來免費,都會運行下一份工作。 – jhouse 2011-04-11 13:41:08

+0

我認爲公平性來自線程池外的線程,runInThread和blockForAvailableThreads都是不公平的。當你說,「當我的線程池超時」是什麼意思? – sbridges 2011-04-11 14:20:52

+0

runInThread()和blockForAvailableThreads()都是從同一個線程中調用的 - 沒有多個線程等待這些方法的結果,所以'公平' wait()/ notify()無關緊要。 (只有一個線程服務/利用線程池)。 – jhouse 2011-04-11 17:34:59

2

我聽起來好像你遇到了一個不適應的場景(一個場景中有更多的工作可以執行,而不是有工作線程)。在觸發器上設置失火指令和/或優先級屬性,以改變它們在超過其觸發時間後的行爲。另外,您可以考慮增加失火閾值,這會改變觸發器可能「遲到」等待線程執行的時間,然後纔會被視爲失火(並且已將其失火指令應用於其中) )。

一旦Quartz ThreadPool中的空間變得可用,是否可以讓我的等待(失火)作業按照它們被觸發的順序被觸發?

「什麼都不做」指示將使火災時間保持原樣。

+0

這絕對是一個失火的場景 - 我已經更新了這個問題,在這一點上更具體。是否有失火指示可以使失火的工作按照他們最初被解僱的順序獲得? – 2011-05-20 14:47:32

+3

用於MISFIRE_INSTRUCTION_DO_NOTHING失火的javadoc的內容如下:「指示調度程序,在發生火災的情況下,CronTrigger希望在當前時間之後的下一次調度中將下一次火災時間更新,但它確實如此現在不想被解僱。「也許我誤解了,但對我來說這聽起來像是工作只會在下一次觸發之前跳過射擊並且什麼也不做。這不是我想要的。我希望在有線程可用時儘快運行該作業,但如果存在多個失火作業,則等待最長的作業首先運行。 – 2011-05-20 15:13:54

0

CronTrigger的情況下,方法updateAfterMisfire()可以重新安排任務new Date()案例MISFIRE_INSTRUCTION_FIRE_ONCE_NOW策略。

如果有幾個任務發生故障,由於計算機運行速度很快,因此可能會同時重新安排幾個任務(同一毫秒)。

因此,如果沒有定義優先級,調度器將根據密鑰或全名接收第一個下一個任務,全部使用相同的NextFireTime

updateAfterMisfire()方法應該使用Thread.sleep(25)作爲示例將任務重新安排到唯一的date

相關問題