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://blog.csdn.net/u010648555
Quartz源码——Quartz调度器的Misfire处理规则(四)的更多相关文章
- pyspider源码解读--调度器scheduler.py
pyspider源码解读--调度器scheduler.py scheduler.py首先从pyspider的根目录下找到/pyspider/scheduler/scheduler.py其中定义了四个类 ...
- spark[源码]-DAG调度器源码分析[二]
前言 根据图片上的结构划分我们不难发现当rdd触发action操作之后,会调用SparkContext的runJob方法,最后调用的DAGScheduler.handleJobSubmitted方法完 ...
- Quartz源码——QuartzSchedulerThread.run() 源码分析(三)
QuartzSchedulerThread.run()是主要处理任务的方法!下面进行分析,方便自己查看! 我都是分析的jobStore 方式为jdbc的SimpleTrigger!RAM的方式类似分析 ...
- quartz源码解析--转
quartz源码解析(一) . http://ssuupv.blog.163.com/blog//146156722013829111028966/ 任何个人.任何企业.任何行业都会有作业调度的需求 ...
- Quartz源码分析
先简单介绍一下quartz,Quartz是一个功能丰富的开源作业调度库,可以集成到几乎任何Java应用程序中 - 从最小的独立应用程序到最大的电子商务系统.quartz可用于创建执行数十,数百甚至数十 ...
- quartz源码分析——执行引擎和线程模型
title: quartz源码分析--执行引擎和线程模型 date: 2017-09-09 23:14:48 categories: quartz tags: [quartz, 源码分析] --- - ...
- quartz源码解析(一)
本文的起因源于一次quartz的异常,在win2003正常运行的程序放在linux环境就抛出异常了,虽然找出异常没花我多长时间,不过由此加深了对quzrtz的了解:古人说,三折肱,为良医,说明经验对于 ...
- Spring AOP 源码分析 - 拦截器链的执行过程
1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...
- .NET零基础入门之02:源码控制管理器的使用
一:概述 源码控制管理器,也叫"版本控制"软件,用于存储.追踪目录(文件夹)和文件的修改历史,是软件开发者的必备工具,是专业软件公司的基础工具.它主要是协助在多人团队中控制代码,防 ...
随机推荐
- python+selenium自动化软件测试(第6章):selenium phantomjs页面解析使用
我们都知道Selenium是一个Web的自动化测试工具,可以在多平台下操作多种浏览器进行各种动作,比如运行浏览器,访问页面,点击按钮,提交表单,浏览器窗口调整,鼠标右键和拖放动作,下拉框和对话框处理等 ...
- ASP.Net Core WebApi几种版本控制对比
版本控制的好处: (1)助于及时推出功能, 而不会破坏现有系统. (2)它还可以帮助为选定的客户提供额外的功能. API 版本控制可以采用不同的方式进行控制,方法如下: (1)在 URL 中追加版本或 ...
- 多模字符串匹配算法之AC自动机—原理与实现
简介: 本文是博主自身对AC自动机的原理的一些理解和看法,主要以举例的方式讲解,同时又配以相应的图片.代码实现部分也予以明确的注释,希望给大家不一样的感受.AC自动机主要用于多模式字符串的匹配,本质上 ...
- 转载 Java基本数据类型
Java语言是静态类型的(statical typed),也就是说所有变量和表达式的类型再编译时就已经完全确定.由于是statical typed,导致Java语言也是强类型(Strong typed ...
- Oracle:解锁scott用户及设置密码
关于Oracle 10g scott用户解锁的方法两则 解决方法一. 首先确认已经安装oracle 数据库和客户端 在客户端DOS下执行如下语句: 注意提示符号 c:\sqlplus /nolog s ...
- HTTP请求范例
package com.grefr.basemethod; /*JAVA发送HTTP请求,返回HTTP响应内容,实例及应用 博客分类: JAVA实现 Java.netBeanJDKApache . J ...
- Java 强引用 软引用 弱引用 虚引用详解
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt393 众所周知,java中是JVM负责内存的分配和回收,这是它的优点(使用方 ...
- JS常用方法总结
1.javascript删除元素节点 IE中有这样一个方法:removeNode(),这个方法在IE下是好使的,但是在Firefox等标准浏览器中就会报错了 removeNode is not def ...
- HTML解析原理概括(转载)
HTML解析原理 标准的web前端工程师需要知道 ◎浏览器(或者相应播放器)的渲染/重绘原理 这我得加把劲了.我还真的说的不是很清楚,我就G下,结果不是很多,找到了有一个,就记下来了... 以下部分 ...
- 团队作业9——测试与发布(Beta版本)
Deadline: 2017-6-5 22:00PM,以博客发表日期为准 评分基准: 按时交 - 有分,检查的项目包括后文的两个方面 测试报告 发布说明 展示博客(单独一篇博客) 晚交 - 0分 迟交 ...