博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Quartz调度器的Misfire处理规则
阅读量:7217 次
发布时间:2019-06-29

本文共 10752 字,大约阅读时间需要 35 分钟。

hot3.png

调度(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

CronTrigger的misfire机制—-默认的 Trigger.MISFIRE_INSTRUCTION_SMART_POLICY !!! 

org.quartz.impl.triggers.AbstractTrigger.updateAfterMisfire(Calendar cal)

getMisfireInstruction() —-> misfireInstruction == 0    

 

通过分析org.quartz.impl.triggers.AbstractTrigger.updateAfterMisfire的源码发现,默认的misfire机制等价于: MISFIRE_INSTRUCTION_FIRE_ONCE_NOW

CronScheduleBuilder csb = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");csb.withMisfireHandlingInstructionDoNothing();csb.withMisfireHandlingInstructionFireAndProceed();csb.withMisfireHandlingInstructionIgnoreMisfires();withMisfireHandlingInstructionDoNothing ---> misfireInstruction = 2——不触发立即执行——等待下次Cron触发频率到达时刻开始按照Cron频率依次执行withMisfireHandlingInstructionFireAndProceed ---> misfireInstruction = 1——以当前时间为触发频率立刻触发一次执行——然后按照Cron频率依次执行withMisfireHandlingInstructionIgnoreMisfires ---> misfireInstruction = -1——以错过的第一个频率时间立刻开始执行——重做错过的所有频率周期后——当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行

 

updateAfterMisfire 方法源码:

/**     * 

* Updates the CronTrigger's state based on the * MISFIRE_INSTRUCTION_XXX that was selected when the CronTrigger * was created. *

* *

* If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY, * then the following scheme will be used:

*

    *
  • The instruction will be interpreted as MISFIRE_INSTRUCTION_FIRE_ONCE_NOW *
*

*//* 根据创建CronTrigger时选择的MISFIRE_INSTRUCTION_XXX更新CronTrigger的状态。如果失火指令设置为MISFIRE_INSTRUCTION_SMART_POLICY,则将使用以下方案:•指令将解释为MISFIRE_INSTRUCTION_FIRE_ONCE_NOW*/ @Override public void updateAfterMisfire(org.quartz.Calendar cal) { int instr = getMisfireInstruction();//获取misfire的值,默认为0 if(instr == Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY)//instr == -1 return; if (instr == MISFIRE_INSTRUCTION_SMART_POLICY) {//instr == 0 instr = MISFIRE_INSTRUCTION_FIRE_ONCE_NOW;//instr = 1 } if (instr == MISFIRE_INSTRUCTION_DO_NOTHING) {//instr == 2 Date newFireTime = getFireTimeAfter(new Date()); while (newFireTime != null && cal != null && !cal.isTimeIncluded(newFireTime.getTime())) { newFireTime = getFireTimeAfter(newFireTime); } setNextFireTime(newFireTime); } else if (instr == MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) {//instr == 1 setNextFireTime(new Date()); } }

 

 

SimpleTrigger

SimpleTrigger的misfire机制 默认的 Trigger.MISFIRE_INSTRUCTION_SMART_POLICY !!!

trig.updateAfterMisfire(cal); 

getMisfireInstruction() —-> misfireInstruction == 0 
——以当前时间为触发频率立即触发执行

SimpleScheduleBuilder ssb = SimpleScheduleBuilder.simpleSchedule();ssb.withMisfireHandlingInstructionFireNow();//1ssb.withMisfireHandlingInstructionIgnoreMisfires();//2ssb.withMisfireHandlingInstructionNextWithExistingCount();//3ssb.withMisfireHandlingInstructionNextWithRemainingCount();//4ssb.withMisfireHandlingInstructionNowWithExistingCount();//5ssb.withMisfireHandlingInstructionNowWithRemainingCount();//6//1withMisfireHandlingInstructionFireNow  ---> misfireInstruction == 1——以当前时间为触发频率立即触发执行——执行至FinalTIme的剩余周期次数——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值//2withMisfireHandlingInstructionIgnoreMisfires ---> misfireInstruction == -1—以错过的第一个频率时间立刻开始执行——重做错过的所有频率周期——当下一次触发频率发生时间大于当前时间以后,按照Interval的依次执行剩下的频率——共执行RepeatCount+1次//3withMisfireHandlingInstructionNextWithExistingCount ---> misfireInstruction == 5——不触发立即执行——等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数——以startTime为基准计算周期频率,并得到FinalTime——即使中间出现pause,resume以后保持FinalTime时间不变//4withMisfireHandlingInstructionNextWithRemainingCount ---> misfireInstruction = 4——不触发立即执行——等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数——以startTime为基准计算周期频率,并得到FinalTime——即使中间出现pause,resume以后保持FinalTime时间不变//5withMisfireHandlingInstructionNowWithExistingCount ---> misfireInstruction = 2——以当前时间为触发频率立即触发执行——执行至FinalTIme的剩余周期次数——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值//6withMisfireHandlingInstructionNowWithRemainingCount --- >misfireInstruction = 3——以当前时间为触发频率立即触发执行——执行至FinalTIme的剩余周期次数——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT 值为 3——此指令导致trigger忘记原始设置的starttime和repeat-count——触发器的repeat-count将被设置为剩余的次数——这样会导致后面无法获得原始设定的starttime和repeat-count值

 

updateAfterMisfire 方法源码:

/**     * 

* Updates the SimpleTrigger's state based on the * MISFIRE_INSTRUCTION_XXX that was selected when the SimpleTrigger * was created. *

* *

* If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY, * then the following scheme will be used:

*

    *
  • If the Repeat Count is 0, then the instruction will * be interpreted as MISFIRE_INSTRUCTION_FIRE_NOW.
  • *
  • If the Repeat Count is REPEAT_INDEFINITELY, then * the instruction will be interpreted as MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT. * WARNING: using MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT * with a trigger that has a non-null end-time may cause the trigger to * never fire again if the end-time arrived during the misfire time span. *
  • *
  • If the Repeat Count is > 0, then the instruction * will be interpreted as MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT. *
  • *
*

* *//*基于在创建SimpleTrigger时选择的MISFIRE_INSTRUCTION_XXX更新SimpleTrigger的状态。如果失火指令设置为MISFIRE_INSTRUCTION_SMART_POLICY,则将使用以下方案:•如果重复计数为0,则指令将解释为MISFIRE_INSTRUCTION_FIRE_NOW。•如果重复计数为REPEAT_INDEFINITELY,则指令将解释为MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT。 警告:如果触发器具有非空的结束时间,则使用MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT可能会导致触发器在失火时间范围内到达结束时,不会再次触发。•如果重复计数大于0,则指令将解释为MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT。*/ @Override public void updateAfterMisfire(Calendar cal) { int instr = getMisfireInstruction();//获取misfire的值,默认为0 if(instr == Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY)//instr == -1 return; if (instr == Trigger.MISFIRE_INSTRUCTION_SMART_POLICY) { //instr == 1 if (getRepeatCount() == 0) { instr = MISFIRE_INSTRUCTION_FIRE_NOW; //instr = 1 } else if (getRepeatCount() == REPEAT_INDEFINITELY) {//getRe..Count == -1 //instr = 4 instr = MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT; } else { // if (getRepeatCount() > 0) instr = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT;//instr == 2 } //instr == 1 } else if (instr == MISFIRE_INSTRUCTION_FIRE_NOW && getRepeatCount() != 0) { //instr == 3 instr = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT; } if (instr == MISFIRE_INSTRUCTION_FIRE_NOW) { //instr == 1 setNextFireTime(new Date()); //instr == 5 } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT) { Date newFireTime = getFireTimeAfter(new Date()); while (newFireTime != null && cal != null && !cal.isTimeIncluded(newFireTime.getTime())) { newFireTime = getFireTimeAfter(newFireTime); if(newFireTime == null) break; //avoid infinite loop java.util.Calendar c = java.util.Calendar.getInstance(); c.setTime(newFireTime); if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) { newFireTime = null; } } setNextFireTime(newFireTime); //instr == 4 } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT) { Date newFireTime = getFireTimeAfter(new Date()); while (newFireTime != null && cal != null && !cal.isTimeIncluded(newFireTime.getTime())) { newFireTime = getFireTimeAfter(newFireTime); if(newFireTime == null) break; //avoid infinite loop java.util.Calendar c = java.util.Calendar.getInstance(); c.setTime(newFireTime); if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) { newFireTime = null; } } if (newFireTime != null) { int timesMissed = computeNumTimesFiredBetween(nextFireTime, newFireTime); setTimesTriggered(getTimesTriggered() + timesMissed); } setNextFireTime(newFireTime); } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT) { //instr == 2 Date newFireTime = new Date(); if (repeatCount != 0 && repeatCount != REPEAT_INDEFINITELY) { setRepeatCount(getRepeatCount() - getTimesTriggered()); setTimesTriggered(0); } if (getEndTime() != null && getEndTime().before(newFireTime)) { setNextFireTime(null); // We are past the end time } else { setStartTime(newFireTime); setNextFireTime(newFireTime); } } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT) { //instr == 3 Date newFireTime = new Date(); int timesMissed = computeNumTimesFiredBetween(nextFireTime, newFireTime); if (repeatCount != 0 && repeatCount != REPEAT_INDEFINITELY) { //repeatCount == -1 int remainingCount = getRepeatCount() - (getTimesTriggered() + timesMissed); if (remainingCount <= 0) { remainingCount = 0; } setRepeatCount(remainingCount); setTimesTriggered(0); } if (getEndTime() != null && getEndTime().before(newFireTime)) { setNextFireTime(null); // We are past the end time } else { setStartTime(newFireTime); setNextFireTime(newFireTime); } } }

 

转载于:https://my.oschina.net/trydaydayup/blog/1539960

你可能感兴趣的文章
异常备忘:java.lang.UnsupportedClassVersionError: Bad version number in .class file
查看>>
最全三大框架整合(使用映射)——applicationContext.xml里面的配置
查看>>
初步理解Java的三大特性——封装、继承和多态
查看>>
知识点积累(一)
查看>>
iphone-common-codes-ccteam源代码 CCFile.m
查看>>
python:浅析python 中__name__ = '__main__' 的作用
查看>>
修改tomcat端口后不能IP访问问题
查看>>
review board
查看>>
URAL 1495 One-two, One-two 2
查看>>
牛客国庆集训派对Day3 G Stones
查看>>
虚函数简单总结
查看>>
插入排序--算法导论
查看>>
NoSQL -- Redis使用
查看>>
处理iphone的 .play() 不能播放问题
查看>>
jetty404web界面服务器信息隐藏
查看>>
22个Photoshop网页设计教程网站推荐
查看>>
如何让程序员更容易的开发Web界面?重构SmartAdmin展示TinyUI
查看>>
centos7 python2和python3共存
查看>>
rhel6.2配置在线yum源
查看>>
分级聚类算法
查看>>