Quartz源码——Quartz调度器的Misfire处理规则(四)
Quartz调度器的Misfire处理规则
调度器的启动和恢复中使用的misfire机制,还需细化!
SimpleTrigger的misfire机制 默认的 Trigger.MISFIRE_INSTRUCTION_SMART_POLICY !!!
trig.updateAfterMisfire(cal);
getMisfireInstruction() ----> misfireInstruction == 0
——以当前时间为触发频率立即触发执行
SimpleScheduleBuilder ssb = SimpleScheduleBuilder.simpleSchedule();
ssb.withMisfireHandlingInstructionFireNow();//1
ssb.withMisfireHandlingInstructionIgnoreMisfires();//2
ssb.withMisfireHandlingInstructionNextWithExistingCount();//3
ssb.withMisfireHandlingInstructionNextWithRemainingCount();//4
ssb.withMisfireHandlingInstructionNowWithExistingCount();//5
ssb.withMisfireHandlingInstructionNowWithRemainingCount();//6
//1
withMisfireHandlingInstructionFireNow ---> misfireInstruction == 1
——以当前时间为触发频率立即触发执行
——执行至FinalTIme的剩余周期次数
——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值
//2
withMisfireHandlingInstructionIgnoreMisfires ---> misfireInstruction == -1
—以错过的第一个频率时间立刻开始执行
——重做错过的所有频率周期
——当下一次触发频率发生时间大于当前时间以后,按照Interval的依次执行剩下的频率
——共执行RepeatCount+1次
//3
withMisfireHandlingInstructionNextWithExistingCount ---> misfireInstruction == 5
——不触发立即执行
——等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数
——以startTime为基准计算周期频率,并得到FinalTime
——即使中间出现pause,resume以后保持FinalTime时间不变
//4
withMisfireHandlingInstructionNextWithRemainingCount ---> misfireInstruction = 4
——不触发立即执行
——等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数
——以startTime为基准计算周期频率,并得到FinalTime
——即使中间出现pause,resume以后保持FinalTime时间不变
//5
withMisfireHandlingInstructionNowWithExistingCount ---> misfireInstruction = 2
——以当前时间为触发频率立即触发执行
——执行至FinalTIme的剩余周期次数
——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值
//6
withMisfireHandlingInstructionNowWithRemainingCount --- >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 方法源码:
/**
* <p>
* Updates the <code>SimpleTrigger</code>'s state based on the
* MISFIRE_INSTRUCTION_XXX that was selected when the <code>SimpleTrigger</code>
* was created.
* </p>
*
* <p>
* If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY,
* then the following scheme will be used: <br>
* <ul>
* <li>If the Repeat Count is <code>0</code>, then the instruction will
* be interpreted as <code>MISFIRE_INSTRUCTION_FIRE_NOW</code>.</li>
* <li>If the Repeat Count is <code>REPEAT_INDEFINITELY</code>, then
* the instruction will be interpreted as <code>MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT</code>.
* <b>WARNING:</b> 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.
* </li>
* <li>If the Repeat Count is <code>> 0</code>, then the instruction
* will be interpreted as <code>MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT</code>.
* </li>
* </ul>
* </p>
* */
/*
基于在创建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);
}
}
}
CronTrigger的misfire机制----默认的 Trigger.MISFIRE_INSTRUCTION_SMART_POLICY !!!
trig.updateAfterMisfire(cal);
getMisfireInstruction() ----> misfireInstruction == 0
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 方法源码:
/**
* <p>
* Updates the <code>CronTrigger</code>'s state based on the
* MISFIRE_INSTRUCTION_XXX that was selected when the <code>CronTrigger</code>
* was created.
* </p>
*
* <p>
* If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY,
* then the following scheme will be used: <br>
* <ul>
* <li>The instruction will be interpreted as <code>MISFIRE_INSTRUCTION_FIRE_ONCE_NOW</code>
* </ul>
* </p>
*/
/*
根据创建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());
}
}
参考文章:https://my.oschina.net/chenleijava/blog/109904
欢迎访问我的csdn博客,我们一同成长!
"不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!"
版权声明
作者:阿飞云
出处:博客园阿飞云的技术博客--http://www.cnblogs.com/aflyun
您的支持是对博主最大的鼓励,感谢您的认真阅读。
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。