Quartz框架(一)—Quartz的基本配置
Quartz框架(二)—jobstore數(shù)據(jù)庫表字段詳解
Quartz框架(三)—任務(wù)的并行/串行執(zhí)行
Quartz框架(四)—misfire處理機制
Quartz框架(五)— 有狀態(tài)的job和無狀態(tài)job
Quartz框架(六)— Trigger狀態(tài)轉(zhuǎn)換
Quartz框架(七)— Quartz集群原理
Quartz框架(八)— Quartz實現(xiàn)異步通知
Quartz框架(九)— 動態(tài)操作Quartz定時任務(wù)
Quartz框架(十)監(jiān)聽
什么叫做misfire
在Quartz中,當一個持久化的觸發(fā)器因為:
1. 調(diào)度器被關(guān)閉;
2. 線程池沒有可用線程;
3. 項目重啟佩憾;
4. 任務(wù)的串行執(zhí)行鸠信;
而錯過激活時間恼琼,就會發(fā)生激活失斶肽 (misfire)魂务。
此時我們需要明確兩個問題(1)如何判定激活失敿摇考阱;(2)如何處理激活失敗鞠苟;
1. 如何判定激活失敗
在Quartz框架(一)—Quartz的基本配置中乞榨,quartz.properties配置文件中含有一個屬性是misfireThreshold(單位毫秒),用來指定調(diào)度引擎設(shè)置觸發(fā)器超時的“臨界值”当娱。也就是說Quartz對于任務(wù)的超時是有容忍度的吃既。只有超過這個容忍度才會判定位misfire。
quartz.properties的配置文件
#設(shè)置容忍度為12s
org.quartz.jobStore.misfireThreshold = 12000
Corn=[*/2 * * * * ?] 即每兩秒循環(huán)一次
jobDetail每次執(zhí)行需要7s
@Component
@DisallowConcurrentExecution
public class TestJob2 extends CustomQuartzJobBean{
private Logger logger = LoggerFactory.getLogger(TestJob2.class);
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
logger.info("【數(shù)據(jù)庫配置定時】-【開始】");
try {
Thread.sleep(7000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("【數(shù)據(jù)庫配置定時】-【結(jié)束】");
}
}
任務(wù)編號 | 預(yù)定運行時刻 | 實際運行時刻 | 延遲量(秒) |
---|---|---|---|
1 | 17:54:00 | 17:54:00 | 0 |
2 | 17:54:02 | 17:54:07 | 5 |
3 | 17:54:04 | 17:54:14 | 10 |
4 | 17:54:06 | 17:54:21 | misfire |
從表中可以看到跨细,每一次任務(wù)的延遲都是5s作用鹦倚,該延遲量不斷累積,并且與misfireThreshold比較冀惭,直到在17:54:21時發(fā)生了misfire震叙,那么17:54:21第4次任務(wù)會不會執(zhí)行呢掀鹅,答案是不一定的,取決于配置媒楼。
2. 激活失敗的處理
激活失敗指令(Misfire Instruction[因死抓可神 指令]
)是觸發(fā)器的一個重要配置乐尊。所有類型的觸發(fā)器都有一個默認的指令:
Trigger.MISFIRE_INSTRUCTION_SMART_POLICY
但是這個“機智策略(policy [跑了誰]
)”對于不同類型的觸發(fā)器其具體行為是不同的。
misfire Instruction在qutz_triggers表中的字段划址。
代碼中設(shè)置misfire策略的方式扔嵌。
2.1 quartz中CornTrigger使用的策略
//所有的misfile任務(wù)馬上執(zhí)行
public static final int MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1;
//在Trigger中默認選擇MISFIRE_INSTRUCTION_FIRE_ONCE_NOW 策略
public static final int MISFIRE_INSTRUCTION_SMART_POLICY = 0;
// CornTrigger默認策略,合并部分misfire夺颤,正常執(zhí)行下一個周期的任務(wù)痢缎。
public static final int MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1;
//所有的misFire都不管,執(zhí)行下一個周期的任務(wù)拂共。
public static final int MISFIRE_INSTRUCTION_DO_NOTHING = 2;
- 可以通過setMisfireInstruction方法設(shè)置misfire策略牺弄。
CronTriggerFactoryBean triggerFactoryBean = new CronTriggerFactoryBean();
triggerFactoryBean.setName("corn_" + clazzName);
triggerFactoryBean.setJobDetail(jobFactory.getObject());
triggerFactoryBean.setCronExpression(quartzCorn);
triggerFactoryBean.setGroup(QUARTZ_TRIGGER_GROUP);
//設(shè)置misfire策略
triggerFactoryBean.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY);
triggerFactoryBean.afterPropertiesSet();
- 也可以通過CronScheduleBuilder設(shè)置misfire策略姻几。
CronScheduleBuilder csb = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");
//MISFIRE_INSTRUCTION_DO_NOTHING
csb.withMisfireHandlingInstructionDoNothing();
//MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
csb.withMisfireHandlingInstructionFireAndProceed();//(默認)
//MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
csb.withMisfireHandlingInstructionIgnoreMisfires();
策略的具體含義
前提:在每個星期周一下午5點到7點宜狐,每隔一個小時執(zhí)行一次,理論上共執(zhí)行3次蛇捌。
1. 情景一:
//所有misfire的任務(wù)會馬上執(zhí)行
public static final int MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1;
若是5點misfire抚恒,6:15系統(tǒng)恢復(fù)之后,5,6點的misfire會馬上執(zhí)行络拌。
2. 情景二:
//不做任何事情
public static final int MISFIRE_INSTRUCTION_DO_NOTHING = 2;
若是5點misfire俭驮,6:15系統(tǒng)恢復(fù)之后,只會執(zhí)行7點的misfire春贸。如果下次執(zhí)行時間超過了end time混萝,實際上就沒有執(zhí)行機會了。
3. 情景三:(cronTrigger的默認策略)
// CornTrigger默認策略萍恕,合并部分misfire逸嘀,正常執(zhí)行下一個周期的任務(wù)。
public static final int MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1;
若是5點misfire允粤,6:15系統(tǒng)恢復(fù)之后崭倘,立刻執(zhí)行一次(只會一次)misfire。
2.2 quartz中SImpleTrigger使用的策略
-
若是使用
MISFIRE_INSTRUCTION_SMART_POLICY
—機智的策略- 如果Repeat=0; 【重復(fù)0次】
instruction selected = MISFIRE_INSTRUCTION_FIRE_NOW;【立刻執(zhí)行类垫,對于不會重復(fù)執(zhí)行的任務(wù)司光,只是默認的處理策略∠せ迹】 - 如果Repeat Count=REPEAT_INDEFINITELY;【無限重復(fù)】
instruction selected = MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT;【在下一個激活點執(zhí)行残家,且錯過的執(zhí)行機會作廢∈墼辏】 - 如果Repeat Count>0;【有限重復(fù)】
instruction selected = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT;【立即執(zhí)行坞淮,并執(zhí)行指定的次數(shù)谴仙。】
- 如果Repeat=0; 【重復(fù)0次】
3. misfire的執(zhí)行流程
- 若配置(默認為true碾盐,可配置)成獲取鎖前先檢查是否有需要recovery的trigger晃跺,先獲取misfireCount;
- 獲取TRIGGER_ACCESS鎖毫玖;
- misfired的判斷依據(jù):status=waiting掀虎,current_time-next_fire_time>misfireThreshold(可配置,默認1分鐘)【即實際觸發(fā)時間-預(yù)計觸發(fā)時間大于容忍度時間】付枫,獲取misfired的trigger烹玉,默認一個事務(wù)中只能最大有20個misfired trigger(可配置)。
- updateAfterMisfired:獲取misfired的策略(默認是MISFIRE_INSTRUCTION_SMART_POLICY該策略在CronTrigger中為MISFIRE_INSTRUCTION_FIRE_ONCE_NOW)阐滩,根據(jù)策略更新nexFireTime二打。
- 將nextFireTime等更新到trigger表;
- commit connection掂榔,釋放鎖继效。