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>&gt; 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://blog.csdn.net/u010648555

Quartz源码——Quartz调度器的Misfire处理规则(四)的更多相关文章

  1. pyspider源码解读--调度器scheduler.py

    pyspider源码解读--调度器scheduler.py scheduler.py首先从pyspider的根目录下找到/pyspider/scheduler/scheduler.py其中定义了四个类 ...

  2. spark[源码]-DAG调度器源码分析[二]

    前言 根据图片上的结构划分我们不难发现当rdd触发action操作之后,会调用SparkContext的runJob方法,最后调用的DAGScheduler.handleJobSubmitted方法完 ...

  3. Quartz源码——QuartzSchedulerThread.run() 源码分析(三)

    QuartzSchedulerThread.run()是主要处理任务的方法!下面进行分析,方便自己查看! 我都是分析的jobStore 方式为jdbc的SimpleTrigger!RAM的方式类似分析 ...

  4. quartz源码解析--转

    quartz源码解析(一)  . http://ssuupv.blog.163.com/blog//146156722013829111028966/ 任何个人.任何企业.任何行业都会有作业调度的需求 ...

  5. Quartz源码分析

    先简单介绍一下quartz,Quartz是一个功能丰富的开源作业调度库,可以集成到几乎任何Java应用程序中 - 从最小的独立应用程序到最大的电子商务系统.quartz可用于创建执行数十,数百甚至数十 ...

  6. quartz源码分析——执行引擎和线程模型

    title: quartz源码分析--执行引擎和线程模型 date: 2017-09-09 23:14:48 categories: quartz tags: [quartz, 源码分析] --- - ...

  7. quartz源码解析(一)

    本文的起因源于一次quartz的异常,在win2003正常运行的程序放在linux环境就抛出异常了,虽然找出异常没花我多长时间,不过由此加深了对quzrtz的了解:古人说,三折肱,为良医,说明经验对于 ...

  8. Spring AOP 源码分析 - 拦截器链的执行过程

    1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...

  9. .NET零基础入门之02:源码控制管理器的使用

    一:概述 源码控制管理器,也叫"版本控制"软件,用于存储.追踪目录(文件夹)和文件的修改历史,是软件开发者的必备工具,是专业软件公司的基础工具.它主要是协助在多人团队中控制代码,防 ...

随机推荐

  1. python的引用计数分析(二)

    python所有对象引用计数被减少1的情况: 一.对象的别名被赋予新的对象; a = 23345455 # 增加了一个引用 b = a # 增加了一个引用 print(sys.getrefcount( ...

  2. iphone 4s页面引用jssdk无效

    今天在做项目的时候,发现了一个bug,用户在iphone 4s上使用该项目打开网页时,调用上传图片的接口没反应. 无语啊.找了半天也没找到是什么问题.

  3. spring mvc:日志对象logger的复用

    在采用Spring mvc+org.slf4j.Logger开发项目时,发现几乎每个controller或者manager都有的一个标配: private final static Logger LO ...

  4. Linq 实现sql中的not in和in条件查询

    T-SQL的IN: Select ProductID, ProductName, CategoryID From dbo.Products Where CategoryID in (1, 2) T-S ...

  5. 附录:MySQL忘记root密码

    中小型规模网站集群架构:MySQL忘记root密码 : 矮哥linux运维群:93324526 前言 你忘记系统root密码的时候,你怎么解决的? 不就是single用户进行修改密码吗?这里原理是类似 ...

  6. [转载]浏览器事件window.onload、onfocus、onblur、ons

    原文地址:浏览器事件window.onload.onfocus.onblur.onscroll和resize作者:lilyxiao <html> <head> <titl ...

  7. 扫雷游戏制作过程(C#描述):第三节、雷区绘制

    前言 这里给出教程原文地址. 该项目已经放在github上托管. 绘制雷区 这一节我们主要涉及界面中雷区的绘制.绘制雷区需要三个变量来保存雷区行数.列数.以及地雷的数量.而且我们希望能够自动获取上次游 ...

  8. 201521123019 《Java程序设计》第8周学习总结

    1. 本章学习总结 2. 书面作业 一.List中指定元素的删除(题目4-1) for (int i = list.size()-1; i >=0; i--) {//从最后一个元素开始删除 if ...

  9. 201521123027 《JAVA程序设计》第四周学习总结

    1.本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. ①多态:相同方法名,不同实现: ②instanceof运算符:判断父类引用所引用的对象实例的实 ...

  10. 201521123119《Java程序设计》第4周学习总结

    1. 本周学习总结 2.书面作业 1.注释的应用 使用类的注释与方法的注释为前面编写的类与方法进行注释,并在Eclipse中查看.(截图) 2.面向对象设计(大作业1,非常重要) 2.1 将在网上商城 ...