quartz-misfire 錯失、補償執行


調度(scheduleJob)或恢復調度(resumeTrigger,resumeJob)后不同的misfire對應的處理規則

misfire產生的條件是:到了該觸發執行時上一個執行還未完成,且線程池中沒有空閑線程可以使用(或有空閑線程可以使用但job設置為@DisallowConcurrentExecution)且過期時間已經超過misfireThreshold就認為是misfire了,錯失觸發了

比如:13:07:24開始執行,重復執行5次,開始執行時,quartz已經計算好每次調度的時間刻,分別如下:

03:33:36,03:33:39,03:33:42,03:33:45,03:33:48,03:33:51

如果第一次執行時間為11s,到03:33:47結束,03:33:47減去03:33:39的時間間隔是8s,如果misfireThreshold設置的時間小於等於8s間隔,則認為是misfire了,如果大於8s間隔,則認為沒有misfire。

 

CronTrigger 

CronScheduleBuilder csb = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");

csb.withMisfireHandlingInstructionDoNothing();
csb.withMisfireHandlingInstructionFireAndProceed();(默認)
csb.withMisfireHandlingInstructionIgnoreMisfires();

  

withMisfireHandlingInstructionDoNothing
——不觸發立即執行
——等待下次Cron觸發頻率到達時刻開始按照Cron頻率依次執行

withMisfireHandlingInstructionIgnoreMisfires
——以錯過的第一個頻率時間立刻開始執行
——重做錯過的所有頻率周期后
——當下一次觸發頻率發生時間大於當前時間后,再按照正常的Cron頻率依次執行

withMisfireHandlingInstructionFireAndProceed(默認)
——以當前時間為觸發頻率立刻觸發一次執行
——然后按照Cron頻率依次執行

SimpleTrigger 

SimpleScheduleBuilder ssb = SimpleScheduleBuilder.simpleSchedule();

ssb.withMisfireHandlingInstructionFireNow();
ssb.withMisfireHandlingInstructionIgnoreMisfires();
ssb.withMisfireHandlingInstructionNextWithExistingCount();
ssb.withMisfireHandlingInstructionNextWithRemainingCount();
ssb.withMisfireHandlingInstructionNowWithExistingCount();  (默認)
ssb.withMisfireHandlingInstructionNowWithRemainingCount();
 
withMisfireHandlingInstructionFireNow
——以當前時間為觸發頻率立即觸發執行
——執行至FinalTIme的剩余周期次數
——以調度或恢復調度的時刻為基准的周期頻率,FinalTime根據剩余次數和當前時間計算得到
——調整后的FinalTime會略大於根據starttime計算的到的FinalTime值
  
withMisfireHandlingInstructionIgnoreMisfires
——以錯過的第一個頻率時間立刻開始執行
——重做錯過的所有頻率周期
——當下一次觸發頻率發生時間大於當前時間以后,按照Interval的依次執行剩下的頻率
——共執行RepeatCount+1次
  
withMisfireHandlingInstructionNextWithExistingCount
——不觸發立即執行
——等待下次觸發頻率周期時刻,執行至FinalTime的剩余周期次數
——以startTime為基准計算周期頻率,並得到FinalTime
——即使中間出現pause,resume以后保持FinalTime時間不變
  
withMisfireHandlingInstructionNextWithRemainingCount
——不觸發立即執行
——等待下次觸發頻率周期時刻,執行至FinalTime的剩余周期次數
——以startTime為基准計算周期頻率,並得到FinalTime
——即使中間出現pause,resume以后保持FinalTime時間不變
  
withMisfireHandlingInstructionNowWithExistingCount(默認)
——以當前時間為觸發頻率立即觸發執行
——執行至FinalTIme的剩余周期次數
——以調度或恢復調度的時刻為基准的周期頻率,FinalTime根據剩余次數和當前時間計算得到
——調整后的FinalTime會略大於根據starttime計算的到的FinalTime值
  
withMisfireHandlingInstructionNowWithRemainingCount
——以當前時間為觸發頻率立即觸發執行
——執行至FinalTIme的剩余周期次數
——以調度或恢復調度的時刻為基准的周期頻率,FinalTime根據剩余次數和當前時間計算得到
——調整后的FinalTime會略大於根據starttime計算的到的FinalTime值

MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
——此指令導致trigger忘記原始設置的starttime和repeat-count
——觸發器的repeat-count將被設置為剩余的次數
——這樣會導致后面無法獲得原始設定的starttime和repeat-count值

  

misfireHandler線程

下面這些原因可能造成 misfired job:

  1. 系統因為某些原因被重啟。在系統關閉到重新啟動之間的一段時間里,可能有些任務會被 misfire;
  2. Trigger 被暫停(suspend)的一段時間里,有些任務可能會被 misfire;
  3. 線程池中所有線程都被占用,導致任務無法被觸發執行,造成 misfire;
  4. 有狀態任務在下次觸發時間到達時,上次執行還沒有結束;為了處理 misfired job,Quartz 中為 trigger 定義了處理策略,主要有下面兩種:MISFIRE_INSTRUCTION_FIRE_ONCE_NOW:針對 misfired job 馬上執行一次;MISFIRE_INSTRUCTION_DO_NOTHING:忽略 misfired job,等待下次觸發;默認是MISFIRE_INSTRUCTION_SMART_POLICY,該策略在CronTrigger中=MISFIRE_INSTRUCTION_FIRE_ONCE_NOW線程默認1分鍾執行一次;在一個事務中,默認一次最多recovery 20個;

執行流程:

  1. 若配置(默認為true,可配置)成獲取鎖前先檢查是否有需要recovery的trigger,先獲取misfireCount;
  2. 獲取TRIGGER_ACCESS鎖;
  3. hasMisfiredTriggersInState:獲取misfired的trigger,默認一個事務里只能最大20個misfired trigger(可配置),misfired判斷依據:status=waiting,next_fire_time < current_time-misfirethreshold(可配置,默認1min)
  4. notifyTriggerListenersMisfired
  5. updateAfterMisfire:獲取misfire策略(默認是MISFIRE_INSTRUCTION_SMART_POLICY,該策略在CronTrigger中=MISFIRE_INSTRUCTION_FIRE_ONCE_NOW),根據策略更新nextFireTime;
  6. 將nextFireTime等更新到trigger表;
  7. commit connection,釋放鎖
  8. 如果還有更多的misfired,sleep短暫時間(為了集群負載均衡),否則sleep misfirethreshold時間,后繼續輪詢;

misfireHandler線程執行流程如下圖所示:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM