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 ...
随机推荐
- 【python密码学编程】5.反转加密法
#Reverse Cipher message = 'there can keep a secret,if two of them are dead.' translated = '' i = len ...
- 链接样式L-O-H-A
伪类可以链接起来使用,即不用在乎顺序 :link{color:blue;} :visited{color:purple;} :link:hover{color:red;} :visited:hover ...
- 关于mac下配置mysql心得
PS:配置一个mysql烦了一天,不过还是有所收获. 首先,下载安装我就不多啰嗦了.关键是在我们安装的最后会有一个临时密码,例如我的PBxsy=ES71(u: 这是非常重要的信息,如果没有得到的话,建 ...
- js的call,apply,bind的使用与区别
在原生js中会有三个很常见的函数,call,apply,bind 他们的作用就是改变当前函数的this指针, 但是细微来说他们还是有不同的. 1)call,apply都是执行某一函数,发现this有变 ...
- css基础知识之属性选择器
css属性选择器及属性和值选择器如下: <!DOCTYPE html> <html lang="en"> <head> <meta cha ...
- Java微信公众平台开发之获取地理位置
本部分需要用到微信的JS-SDK,微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包.通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照.选图.语音.位置等手机系统 ...
- JavaScript 加号运算符详解
将介绍JavaScript中 '+'加号运算符在一元.二元运算时的表现. 目录 1.一元运算符 2. 二元运算符 1. 一元运算符 语法: + Expression 说明:'+'号运算符作为一元运算符 ...
- http基础知识总结
前车之鉴,后车之师. 站在各位前辈的肩膀上学习到很多知识,这里仅做记录,供自己使用 关于HTTP 我们想要打开一个网站,首先是需要往浏览器地址的URL输入框架中输入网址.当敲下回车后,通过http协议 ...
- win7系统中如何使文件显示出扩展名或显示文件后缀名
win7系统中如何使文件显示出扩展名-------------------- 1.点击计算机-->>点击组织,然后选择“文件夹及搜索选项”-->> -------------- ...
- Android学习之旅(一)
2017-02-27 今天开始,正式开启Android学习之旅,背景从事.Net平台开发快五年了,一直在用C#做Web开发. 前天选购了两本书:<Java 编程思想(第四版)>和<第 ...