Quartz的misfire处理机制分析
Quartz是一个特性丰富的开源的任务调度开发库,它可以很方便的集成到你的应用程序中。在Quartz中,当一个持久的触发器因为调度器被关闭或者线程池中没有可用的线程而错过了激活时间时,就会发生激活失败(misfire)。那么,我们需要明确2个问题:如何判定激活失败;如何处理激活失败。
一、激活失败判定
quartz.properties配置文件中有一个属性是misfireThreshold(单位为毫秒),用来指定调度引擎设置触发器超时的"临界值"。也就是说Quartz对于任务的超时是有容忍度的,超过了这个容忍度才会判定misfire。比如说,某触发器设置为,10:15首次激活,然后每隔3秒激活一次,无限次重复。然而该任务每次运行需要10秒钟的时间。可见,每次任务的执行都会超时,那么究竟是否会引起misfire,就取决于misfireThreshold的值了。以第二次任务来说,它的运行时间已经比预定晚了7秒,那么如果misfireThreshold>7000,说明该偏差可容忍,则不算misfire,该任务立刻执行;如果misfireThreshold<=7000,则判定为misfire,根据相关配置策略进行处理。
注意,任务的延迟是有累计的。在前面的例子中,假设misfireThreshold设置为60000,即60秒。那么每次任务的延迟量即是否misfire计算如下:
任务编号 |
预定运行时刻 |
实际运行时刻 |
延迟量(秒) |
备注 |
1 |
10:15 |
10:15 |
0 |
|
2 |
10:18 |
10:25 |
7 |
|
3 |
10:21 |
10:35 |
14 |
|
4 |
10:24 |
10:45 |
21 |
|
5 |
10:27 |
10:55 |
28 |
|
6 |
10:30 |
11:05 |
35 |
|
7 |
10:33 |
11:15 |
42 |
|
8 |
10:36 |
11:25 |
49 |
|
9 |
10:39 |
11:35 |
56 |
|
10 |
10:42 |
11:45 |
63 |
misfire |
从表中可以看到,每一次任务执行都会带来7秒的延迟量,该延迟量不断被与misfireThreshold比较,直到达到该值后,在11:45分发生misfire。那么在11:45第10次任务会不会准时执行呢?答案是不一定,取决于配置。
二、激活失败处理
激活失败指令(Misfire Instructions)是触发器的一个重要属性,它指定了misfire发生时调度器应当如何处理。所有类型的触发器都有一个默认的指令,叫做Trigger.MISFIRE_INSTRUCTION_SMART_POLICY,但是这个这个“聪明策略”对于不同类型的触发器其具体行为是不同的。对于SimpleTrigger,这个“聪明策略”将根据触发器实例的状态和配置来决定其行为。具体如下[]:
如果Repeat Count=0:
instruction selected = MISFIRE_INSTRUCTION_FIRE_NOW;
如果Repeat Count=REPEAT_INDEFINITELY:
instruction selected = MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT;
如果Repeat Count>0:
instruction selected = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT;
下面解释SimpleTrigger常见策略:
MISFIRE_INSTRUCTION_FIRE_NOW
立刻执行。对于不会重复执行的任务,这是默认的处理策略。
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
NEXT指以现在为基准,以repeat interval为周期,延时到下一个激活点执行。WITH_REMAINING_COUNT指超时期内错过的执行机会作废。因此该策略的含义是,在下一个激活点执行,且超时期内错过的执行机会作废。
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_COUNT
立即执行,且超时期内错过的执行机会作废。
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT
WITH_EXISTING_COUNT指,根据已设置的repeat count进行执行。也就是说错过的执行机会不作废,保证实际执行次数满足设置。因此本策略的含义是,在下一个激活点执行,并重复到指定的次数。
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_COUNT
立即执行,并重复到指定的次数。
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
忽略所有的超时状态,按照触发器的策略执行。
对于CronTrigger,该“聪明策略”默认选择MISFIRE_INSTRUCTION_FIRE_ONCE_NOW以指导其行为。
下面解释CronTrigger常见策略:
MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
立刻执行一次,然后就按照正常的计划执行。
MISFIRE_INSTRUCTION_DO_NOTHING
目前不执行,然后就按照正常的计划执行。这意味着如果下次执行时间超过了end time,实际上就没有执行机会了。
三、示例程序1
=====代码=====
JobDetail job1 = newJob(StatefulDumbJob.class).withIdentity("statefulJob1", "group1")
.usingJobData(StatefulDumbJob.EXECUTION_DELAY, 10000L).build(); SimpleTrigger trigger1 = newTrigger().withIdentity("trigger1", "group1").startAt(startTime)
.withSchedule(simpleSchedule().withIntervalInSeconds(3).repeatForever()).build(); Date ft1 = sched.scheduleJob(job1, trigger1);
log.info(job1.getKey() + " will run at: " + ft1 + " and repeat: " + trigger1.getRepeatCount() + " times, every "
+ trigger1.getRepeatInterval() / 1000 + " seconds");
=====代码=====
misfireThreshold设置为60000。
分析:
各任务的延迟量如下表所示:
任务编号 |
预定运行时刻 |
实际运行时刻 |
延迟量(秒) |
备注 |
1 |
16:15:45 |
16:15:45 |
0 |
|
2 |
16:15:48 |
16:15:55 |
7 |
|
3 |
16:15:51 |
16:16:05 |
14 |
|
4 |
16:15:54 |
16:16:15 |
21 |
|
5 |
16:15:57 |
16:16:25 |
28 |
|
6 |
16:16:00 |
16:16:35 |
35 |
|
7 |
16:16:03 |
16:16:45 |
42 |
|
8 |
16:16:06 |
16:16:55 |
49 |
|
9 |
16:16:09 |
16:17:05 |
56 |
|
无 |
16:16:12 |
16:17:15 |
63 |
misfire |
10 |
16:17:18 |
16:17:18 |
0 |
|
11 |
16:17:21 |
16:17:28 |
7 |
在16:17:15发生misfire。因为Repeat Count=REPEAT_INDEFINITELY,所以smart policy选择的策略是MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT。因此,延时3秒后,在16:17:18第10次任务被执行,延迟量清零。当然,程序会一直这样循环下去。
程序输出:
---group1.statefulJob1 executing.[Fri Feb 19 16:15:45 CST 2016]
-group1.statefulJob1 complete (1).
---group1.statefulJob1 executing.[Fri Feb 19 16:15:55 CST 2016]
-group1.statefulJob1 complete (2).
---group1.statefulJob1 executing.[Fri Feb 19 16:16:05 CST 2016]
-group1.statefulJob1 complete (3).
---group1.statefulJob1 executing.[Fri Feb 19 16:16:15 CST 2016]
-group1.statefulJob1 complete (4).
---group1.statefulJob1 executing.[Fri Feb 19 16:16:25 CST 2016]
-group1.statefulJob1 complete (5).
---group1.statefulJob1 executing.[Fri Feb 19 16:16:35 CST 2016]
-group1.statefulJob1 complete (6).
---group1.statefulJob1 executing.[Fri Feb 19 16:16:45 CST 2016]
-group1.statefulJob1 complete (7).
---group1.statefulJob1 executing.[Fri Feb 19 16:16:55 CST 2016]
-group1.statefulJob1 complete (8).
---group1.statefulJob1 executing.[Fri Feb 19 16:17:05 CST 2016]
-group1.statefulJob1 complete (9).
---group1.statefulJob1 executing.[Fri Feb 19 16:17:18 CST 2016]
-group1.statefulJob1 complete (10).
四、示例程序2
=====代码=====
JobDetail job2 = newJob(StatefulDumbJob.class).withIdentity("statefulJob2", "group1")
.usingJobData(StatefulDumbJob.EXECUTION_DELAY, 10000L).build(); SimpleTrigger trigger2 = newTrigger()
.withIdentity("trigger2", "group1")
.startAt(startTime)
.withSchedule(simpleSchedule().withIntervalInSeconds(3).repeatForever()
.withMisfireHandlingInstructionNowWithExistingCount()) // set misfire instructions
.build(); Date ft2 = sched.scheduleJob(job2, trigger2);
log.info(job2.getKey() + " will run at: " + ft2 + " and repeat: " + trigger2.getRepeatCount() + " times, every "
+ trigger2.getRepeatInterval() / 1000 + " seconds");
=====代码=====
misfireThreshold设置为60000。
分析:
示例2与示例1的区别在于,触发器指定了激活失败指令为MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_COUNT。
各任务的延迟量如下表所示:
任务编号 |
预定运行时刻 |
实际运行时刻 |
延迟量(秒) |
备注 |
1 |
17:05:15 |
17:05:15 |
0 |
|
2 |
17:05:18 |
17:05:25 |
7 |
|
3 |
17:05:21 |
17:05:35 |
14 |
|
4 |
17:05:24 |
17:05:45 |
21 |
|
5 |
17:05:27 |
17:05:55 |
28 |
|
6 |
17:05:30 |
17:06:05 |
35 |
|
7 |
17:05:33 |
17:06:15 |
42 |
|
8 |
17:05:36 |
17:06:25 |
49 |
|
9 |
17:05:39 |
17:06:35 |
56 |
|
无 |
17:05:42 |
17:06:45 |
63 |
misfire |
10 |
17:06:45 |
17:06:45 |
0 |
|
11 |
17:05:48 |
17:06:55 |
7 |
在17:06:45发生misfire。根据其激活失败指令,任务10在该时刻被立即执行,延迟量清零。然后,程序继续如此循环下去。
程序输出:
---group1.statefulJob2 executing.[Fri Feb 19 17:05:15 CST 2016]
-group1.statefulJob2 complete (1).
---group1.statefulJob2 executing.[Fri Feb 19 17:05:25 CST 2016]
-group1.statefulJob2 complete (2).
---group1.statefulJob2 executing.[Fri Feb 19 17:05:35 CST 2016]
-group1.statefulJob2 complete (3).
---group1.statefulJob2 executing.[Fri Feb 19 17:05:45 CST 2016]
-group1.statefulJob2 complete (4).
---group1.statefulJob2 executing.[Fri Feb 19 17:05:55 CST 2016]
-group1.statefulJob2 complete (5).
---group1.statefulJob2 executing.[Fri Feb 19 17:06:05 CST 2016]
-group1.statefulJob2 complete (6).
---group1.statefulJob2 executing.[Fri Feb 19 17:06:15 CST 2016]
-group1.statefulJob2 complete (7).
---group1.statefulJob2 executing.[Fri Feb 19 17:06:25 CST 2016]
-group1.statefulJob2 complete (8).
---group1.statefulJob2 executing.[Fri Feb 19 17:06:35 CST 2016]
-group1.statefulJob2 complete (9).
---group1.statefulJob2 executing.[Fri Feb 19 17:06:45 CST 2016]
-group1.statefulJob2 complete (10).
---group1.statefulJob2 executing.[Fri Feb 19 17:06:55 CST 2016]
-group1.statefulJob2 complete (11).
Quartz的misfire处理机制分析的更多相关文章
- quartz群调查调度机制和源代码分析
pageId=85056282#quartz集群调度机制调研及源代码分析-quartz2.2.1集群调度机制调研及源代码分析" style="color:rgb(59,115,17 ...
- Linux mips64r2 PCI中断路由机制分析
Linux mips64r2 PCI中断路由机制分析 本文主要分析mips64r2 PCI设备中断路由原理和irq号分配实现方法,并尝试回答如下问题: PCI设备驱动中断注册(request_irq) ...
- IOS Table中Cell的重用reuse机制分析
IOS Table中Cell的重用reuse机制分析 技术交流新QQ群:414971585 创建UITableViewController子类的实例后,IDE生成的代码中有如下段落: - (UITab ...
- 您还有心跳吗?超时机制分析(java)
注:本人是原作者,首发于并发编程网(您还有心跳吗?超时机制分析),此文结合那里的留言作了一些修改. 问题描述 在C/S模式中,有时我们会长时间保持一个连接,以避免频繁地建立连接,但同时,一般会有一个超 ...
- Java 类反射机制分析
Java 类反射机制分析 一.反射的概念及在Java中的类反射 反射主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.在计算机科学领域,反射是一类应用,它们能够自描述和自控制.这类应用通过某 ...
- Linux信号(signal) 机制分析
Linux信号(signal) 机制分析 [摘要]本文分析了Linux内核对于信号的实现机制和应用层的相关处理.首先介绍了软中断信号的本质及信号的两种不同分类方法尤其是不可靠信号的原理.接着分析了内核 ...
- Java 动态代理机制分析及扩展
Java 动态代理机制分析及扩展,第 1 部分 王 忠平, 软件工程师, IBM 何 平, 软件工程师, IBM 简介: 本文通过分析 Java 动态代理的机制和特点,解读动态代理类的源代码,并且模拟 ...
- Quartz的misfire特性
Quartz的misfire特性 只有一个线程.多个job 第一个job产生misfire(executeTime>Interval) 且是repeatForever 那么只会运行第一个job, ...
- Android内存机制分析1——了解Android堆和栈
//----------------------------------------------------------------------------------- Android内存机制分析1 ...
随机推荐
- 函数&闭包
作用域链 闭包的理解 所谓"闭包",指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. 下面来看一个例子: function ...
- iOS开发 Android开发 移动Web开发
通常,来自移动端的测试需求涉及2类: iOS/Android 移动端H5 因此,需要把基础的概念清清楚楚地落地 Client端 Server端 平台描述 语言 相同 差别 / web平台 web平台开 ...
- C++数组和指针加减法和sizeof问题
关于指针和加减法: 指针的加减法:指针的加减法,加多少或者减多少,主要是看所指对象的sizeof值. 例子: double m = 3.0; ; double *p=&m; int* p1=& ...
- leetcode——262. Trips and Users
The Trips table holds all taxi trips. Each trip has a unique Id, while Client_Id and Driver_Id are b ...
- Mac实用操作技巧(六)
Night Shift,保护你夜间的眼睛 之前在Mac上有一款很著名的软件叫f.lux,这款软件会根据Mac的时间和地理位置,来自动切换屏幕亮度,如果进入晚上则调成暖色,白天就切换成普通颜色.现在Ma ...
- Oracle - 简单理解字符集
起因 今天使用SoapUI来模拟第三方的程序进行测试. 简单来说,流程是我们的程序从SoapUI里面获取数据,然后将数据插入数据库从数据库. SoapUI的脚本来自于第三方,里面包含当地的字符编码,当 ...
- HTML,CSS,JS之间的关系
HTML,CSS,JS之间的关系 本笔记是自己在浏览了各位前辈后拼凑总结下来的知识,供自己使用消化.后面会附上各种链接地址,尊重原创 最准确的网页设计思路是把网页分成三个层次,即:结构层(HTML). ...
- 80C51学习 蜂鸣器
/* 蜂鸣器分为有源和无源 其中有源是指有振荡源 ULN2003 达林顿管 输入输出反向放大 */ #include "reg52.h" typedef unsigned int ...
- 【可视化】Echarts3图层
默认echarts中canvas组件的z-index等于2,所以如果想让一个块元素如div覆盖echarts组件,需要指定z-index:3或者更大
- oracle撤销表空间和回滚段
/* 撤销表空间 */ 通过使用撤销技术,能够为Oracle数据库提供以下功能: * 使用ROLLBACK语句撤销事务 * 进行数据库恢复 * 提供数据的读一致性 Oracle强烈建议DBA在Orac ...