调度(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 theCronTrigger
* 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
*
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 theSimpleTrigger
* 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 asMISFIRE_INSTRUCTION_FIRE_NOW
. * - If the Repeat Count is
REPEAT_INDEFINITELY
, then * the instruction will be interpreted asMISFIRE_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 asMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
. * *