Quartz Scheduler失火指令说明
- 所有工作線程都忙于運(yùn)行其他作業(yè)(可能具有更高的優(yōu)先級)
- 調(diào)度程序本身已關(guān)閉
- 該作業(yè)是在過去的開始時間安排的(可能是編碼錯誤)
您可以通過簡單地在quartz.properties自定義org.quartz.threadPool.threadCount (默認(rèn)值為10)來增加工作線程的數(shù)量。 但是當(dāng)整個應(yīng)用程序/服務(wù)器/調(diào)度程序停機(jī)時,您實際上無法執(zhí)行任何操作。 當(dāng)Quartz無法觸發(fā)給定的觸發(fā)器時,這種情況稱為不點火 。 您知道Quartz在發(fā)生時在做什么嗎? 事實證明,Quartz可以采用多種策略(稱為失火指令 ),并且如果您沒有考慮的話,還有一些默認(rèn)設(shè)置。 但是,為了使您的應(yīng)用程序健壯和可預(yù)測(尤其是在高負(fù)載或維護(hù)情況下),您應(yīng)該真正確保觸發(fā)器和作業(yè)的配置合理。
根據(jù)選擇的觸發(fā)器,有不同的配置選項(可用的失火說明 )。 Quartz的行為也取決于觸發(fā)器設(shè)置(所謂的智能策略 )。 盡管失火說明已在文檔中進(jìn)行了描述,但我發(fā)現(xiàn)很難理解它們的真正含義。 因此,我創(chuàng)建了這篇小總結(jié)文章。
在深入探討細(xì)節(jié)之前,應(yīng)該先介紹另一個配置選項。 它是org.quartz.jobStore.misfireThreshold (以毫秒為單位),默認(rèn)為60000(一分鐘)。 它定義了觸發(fā)器應(yīng)該多長時間才被認(rèn)為觸發(fā)失敗 。 在默認(rèn)設(shè)置下,如果觸發(fā)器是在30秒前觸發(fā)的,那么Quartz會很高興地運(yùn)行它。 這種延遲不被認(rèn)為是錯誤觸發(fā)。 但是,如果在計劃的時間之后61秒發(fā)現(xiàn)觸發(fā)器,則特殊的失火處理程序線程會按照失火指令來處理它。 出于測試目的,我們將此參數(shù)設(shè)置為1000(1秒),以便我們可以快速測試錯火。
簡單觸發(fā),無需重復(fù)
在我們的第一個示例中,我們將看到計劃僅運(yùn)行一次的簡單觸發(fā)器如何處理錯火:
val trigger = newTrigger().startAt(DateUtils.addSeconds(new Date(), -10)).build()相同的觸發(fā)器,但顯式設(shè)置了失火指令處理程序:
val trigger = newTrigger().startAt(DateUtils.addSeconds(new Date(), -10)).withSchedule(simpleSchedule().withMisfireHandlingInstructionFireNow() //MISFIRE_INSTRUCTION_FIRE_NOW).build()為了進(jìn)行測試,我只是將觸發(fā)器安排在10秒鐘前運(yùn)行(因此,它在創(chuàng)建之時要晚10秒鐘!)在現(xiàn)實世界中,您通常不會安排這樣的觸發(fā)器。 而是假設(shè)觸發(fā)器已正確設(shè)置,但是在安排好調(diào)度程序時,調(diào)度程序已關(guān)閉或沒有任何可用的輔助線程。 然而,石英將如何處理這種特殊情況? 在上面的第一個代碼段中,未設(shè)置失火處理指令(在這種情況下,使用了智能策略 )。 第二個代碼段明確定義了發(fā)生錯火時我們期望什么樣的行為。 見表:
簡單觸發(fā)重復(fù)固定次數(shù)
這種情況要復(fù)雜得多。 想象一下,我們已經(jīng)安排了一些工作來重復(fù)固定的次數(shù):
val trigger = newTrigger().startAt(dateOf(9, 0, 0)).withSchedule(simpleSchedule().withRepeatCount(7).withIntervalInHours(1).WithMisfireHandlingInstructionFireNow() //or other).build()在此示例中,假設(shè)觸發(fā)器每小時觸發(fā)8次(首次執(zhí)行+ 7次重復(fù)),從今天上午9點開始( startAt(dateOf(9, 0, 0)) 。因此,最后一次執(zhí)行應(yīng)在下午4點進(jìn)行。假設(shè)由于某種原因,調(diào)度程序無法在上午9點和10點運(yùn)行作業(yè),并且在10:15 AM發(fā)現(xiàn)了這一事實,即2次點火失敗,調(diào)度程序在這種情況下將如何表現(xiàn)?
簡單觸發(fā)無限重復(fù)
在這種情況下,觸發(fā)器以給定的間隔重復(fù)無數(shù)次:
val trigger = newTrigger().startAt(dateOf(9, 0, 0)).withSchedule(simpleSchedule().withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY).withIntervalInHours(1).WithMisfireHandlingInstructionFireNow() //or other).build()再次應(yīng)該從今天的上午9點開始每小時觸發(fā)一次( startAt(dateOf(9, 0, 0)) ( startAt(dateOf(9, 0, 0)) 。然而,調(diào)度程序無法在上午9點和10點運(yùn)行作業(yè),并且它在10:15發(fā)現(xiàn)了這一事實AM,即2次點火失敗,與簡單觸發(fā)器固定運(yùn)行次數(shù)相比,這是更普遍的情況。
CRON觸發(fā)器
CRON觸發(fā)器是Quartz用戶中最受歡迎的觸發(fā)器。 但是,還有兩個其他可用的觸發(fā)器: DailyTimeIntervalTrigger (例如, 每25分鐘觸發(fā)一次 )和CalendarIntervalTrigger (例如, 每5個月觸發(fā)一次 )。 它們支持在CRON和簡單觸發(fā)器中均不可能的觸發(fā)策略。 但是,他們了解與CRON觸發(fā)器相同的失火處理說明。
val trigger = newTrigger().withSchedule(cronSchedule("0 0 9-17 ? * MON-FRI").withMisfireHandlingInstructionFireAndProceed() //or other).build()在此示例中,觸發(fā)器應(yīng)在周一至周五的上午9點至下午5點之間每小時觸發(fā)一次。 但是再次錯過了前兩次調(diào)用(因此觸發(fā)器未觸發(fā)),這種情況在上午10:15被發(fā)現(xiàn)。 請注意,可用的失火指令與簡單觸發(fā)器相比有所不同:
QTZ-283 注 : QTZ-283:MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY不JDBCJobStore工作 -顯然存在一個bug,當(dāng)JDBCJobStore時,留意這個問題。
如您所見,各種觸發(fā)器的行為基于實際設(shè)置而有所不同。 而且,即使提供了所謂的智能策略 ,該決定通常還是基于業(yè)務(wù)需求。 從本質(zhì)上講,有三種主要策略: 忽略 , 立即運(yùn)行,繼續(xù)并丟棄并等待下一個 。 它們都有不同的用例:
當(dāng)您要確保觸發(fā)了所有計劃執(zhí)行時,請使用忽略策略,即使這意味著將觸發(fā)多個未觸發(fā)的觸發(fā)器。 考慮一下一個工作,該工作根據(jù)最后一個小時的訂單每小時生成一次報告。 如果服務(wù)器停機(jī)了8個小時,您仍然希望盡快生成報告。 在這種情況下, 忽略策略將簡單地以計劃程序的速度運(yùn)行在該8個小時內(nèi)計劃的所有觸發(fā)器。 他們將遲到幾個小時,但最終將被執(zhí)行。
當(dāng)有定期執(zhí)行的作業(yè)以及失火情況下,應(yīng)立即使用*策略,但應(yīng)盡快運(yùn)行,但只能運(yùn)行一次。 想一想每分鐘都會清理/tmp目錄的作業(yè)。 如果調(diào)度程序忙了20分鐘并且最終可以運(yùn)行此作業(yè),則您不想運(yùn)行20次! 一個就足夠了,但要確保它能盡快運(yùn)行。 然后回到正常的一分鐘間隔。
最后,當(dāng)您要確保作業(yè)在特定的時間點運(yùn)行時, next *策略很好。 例如,您需要每小時獲取一個季度的股票價格。 它們會Swift變化,因此,如果您的工作失敗了,并且已經(jīng)整整20分鐘了,那就不要打擾了。 您錯過了5分鐘的正確時間,現(xiàn)在您不在乎。 最好有一個差距而不是一個不正確的值。 在這種情況下,Quartz將跳過所有未執(zhí)行的執(zhí)行,而僅等待下一個執(zhí)行。
參考: Quartz調(diào)度程序失火指令,由我們的JCG合作伙伴 Tomasz Nurkiewicz在Java和社區(qū)博客中解釋。
翻譯自: https://www.javacodegeeks.com/2012/04/quartz-scheduler-misfire-instructions.html
總結(jié)
以上是生活随笔為你收集整理的Quartz Scheduler失火指令说明的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 羊肚要煮几分钟才熟 生羊肚煮多长时间能熟
- 下一篇: Google App Engine JA