quartz-misfire 錯失、補償執行

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

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

好比:13:07:24開始執行,重複執行5次,開始執行時,quartz已經計算好每次調度的時間刻,分別以下:負載均衡

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

若是第一次執行時間爲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:3d

  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個;

執行流程:blog

  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線程執行流程以下圖所示:事務

相關文章
相關標籤/搜索