Quartz框架中MisFire的理解
如各位希望转载或引用,请注明出处,尊重原创,谢谢。如有疑问或错误,欢迎邮件沟通。
gitHub地址:https://github.com/thinkingfioa
邮箱地址:thinking_fioa@163.com
博客地址: https://blog.csdn.net/thinking_fioa
本文重点
Quartz框架是Java生态下非常著名的定时任务框架,包括Spring中的诸多定时任务也是依赖于Quartz框架实现的。
本文重点讲解:Quartz框架中的MisFire怎么理解,还有MissFire后的补偿机制。网上非常多的博客,完全在照搬照翻英文文档,没有任何自己的理解,没有任何参考意义。都在搬运垃圾,强烈鄙视。
1. 背景
Quartz框架是Java生态中的一套非常优秀的定时任务框架,使用Quartz框架时,需要注意Quartz强烈依赖主机时间。主机时间的任何飘动,可能导致Quartz定时任务的非预期执行或不执行。
任何定时框架,都可能存在MisFire的现象。何为MisFire,就是:周期性任务A需要在某个规定的时间执行,但是由于某种原因导致任务A未执行,称为MisFire。
Quartz常常由于下列几种情况导致任务的MisFire:
-
Quartz的线程数较少,周期性任务较多且执行时间较长,导致某个时间点需要执行周期性任务A未被CPU调度到,导致MisFire。
-
将本地时间往后调整,直接跨过了周期性任务A,周期性任务A也被MisFire。
-
设置过去的时间为开始执行时间。例如当前时间是9:00:00,指定开始时间为7:00:00
如何设定任务的MisFire和MisFire后的补偿机制非常重要,对于改点官方文档描述较为模糊,网上一大批直接翻译官方文档的博客更是说的云里雾里。
2. 分析
本文主要从两个维度来讲解下Quartz的MisFire机制,帮助使用者能清楚理解自己的周期性任务应该如何设置,避免非预期行为出现。
2.1 如何判定一个任务是MissFire
Quartz判断一个任务是MisFire,提供了一个配置项:org.quartz.jobStore.misfireThreshold,缺省是60000ms(即60秒)。只有任务执行时间延后超过这个配置项阀值,任务才被确认为MisFire状态,随后执行约定的补偿机制。
也就是说,任务执行时间延后未超过misfireThreshold阀值,则会立即执行该任务。
2.2 判定一个任务为MissFire后,Quartz的补偿机制区别
补偿机制只有在任务确认为MisFire状态后,才会被执行。补偿机制比较容易理解,主要以CronTrigger机制为例。
2.2.1 withMisfireHandlingInstructionDoNothing
不触发立即执行,等待下次Cron触发频率到达时刻开始按照Cron频率依次执行。
2.2.2 withMisfireHandlingInstructionIgnoreMisfires
以错过的第一个频率时间立刻开始执行,重做错过的所有频率周期后,当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行
2.2.3 withMisfireHandlingInstructionFireAndProceed(默认)
以当前时间为触发频率立刻触发一次执行,然后按照Cron频率依次执行
3. 案例理解
在实际的开发中,理解misfireThreshold阀值和补偿机制非常重要,在不同的运用场景这两个配置不同,需要做到灵活运用。
在实际使用Quartz时,还有一个点需要注意:定时任务的启动时间点startAt(time)或startAtNow(),这个在预测定时任务第一次执行时非常重要。
下列以使用Cron表达式的Quartz来举例说明。
3.1 案例一
-
cron: 0 0/15 * * * ?
-
startTime(9:00:00)
-
currentTime(10:10:00)
-
org.quartz.jobStore.misfireThreshold= 15 * 60 * 1000ms
-
withMisfireHandlingInstructionFireAndProceed
周期性任务从9:00:00开始,每15分钟执行一次,misfireThreshold=15分钟。当前时间是10:10:00提交任务后,由于任务开始时间是9:00:00,应该在9:00:00、9:15:00、9:30:00、9:45:00、10:00:00执行任务,第一个任务9:00:00执行与当前的时间已经超过misfireThreshold的15分钟,意味着出现了MisFire现象,那么需按照withMisfireHandlingInstructionFireAndProceed补偿策略执行。
预期结果:立即执行一次定时任务,并在10:15:00分钟再次执行任务
3.2 案例二
-
cron: 0 0/15 * * * ?
-
startTime(9:00:00)
-
currentTime(10:10:00)
-
org.quartz.jobStore.misfireThreshold= 15 * 60 * 1000ms
-
withMisfireHandlingInstructionDoNothing
周期性任务从9:00:00开始,每15分钟执行一次,misfireThreshold=15分钟。当前时间是10:10:00提交任务后,由于任务开始时间是9:00:00,应该在9:00:00、9:15:00、9:30:00、9:45:00、10:00:00执行任务,第一个任务9:00:00执行与当前的时间已经超过misfireThreshold的15分钟,意味着出现了MisFire现象,那么需按照withMisfireHandlingInstructionDoNothing补偿策略执行。
预期结果:在10:15:00分钟执行任务
3.3 案例三
-
cron: 0 0/15 * * * ?
-
startTime(9:00:00)
-
currentTime(10:10:00)
-
org.quartz.jobStore.misfireThreshold= 100 * 60 * 1000ms
-
withMisfireHandlingInstructionDoNothing
周期性任务从9:00:00开始,每15分钟执行一次,misfireThreshold=100分钟。当前时间是10:10:00提交任务后,由于任务开始时间是9:00:00,应该在9:00:00、9:15:00、9:30:00、9:45:00、10:00:00执行任务,第一个任务9:00:00执行与当前的时间未超过misfireThreshold的100分钟,意味着任务未出现misFire现象。所有任务立即执行下
预期结果:立即执行5次任务,并在10:15:00分钟再次执行任务