org.quartz.impl.jdbcjobstore.JobStoreSupport recoverMisfiredJobs
一月 21, 2022 7:23:27 上午 org.quartz.impl.jdbcjobstore.JobStoreSupport recoverMisfiredJobs
信息: Handling 5 trigger(s) that missed their scheduled fire-time.
有时候,Quartz并不能如你所愿的运行你的job。这里有3个原因:
1.所有的woker thread(工作线程; 辅助线程)都在运行其他的job
2.scheduler(调度器)down了(关于这个down。我不太明确是shutdown了。。还是挂掉了。因此下文依旧用down。)
3.任务被安排在过去的某一时刻启动(此可能为代码错误)
你可以简单地通过配置quartz.properties文件中的org.quartz.threadPool.threadCount,这方法仍然是无效的。这种Quartz无法启动指定触发器情况,汉语无法贴切表达)。
你知道当这种情况发生的时候,Quartz有许多的策略(叫misfire instructions,并且当你没有去想这方面问题的时候,你应该有意识的去确保triggers 和 jobs工作正常。
基于你用的,会有不同的配置选项(对misfire instructions有效)。当然trigger也会使Quartz有不同的行为(叫做smart policy,但是我发现都很难理解它所想表达的意思,我写下这篇简短的总结。
在我深入细节之前,默认是60000(一分钟)。它定义了
基于默认配置trigger应该在30秒以前被触发,Quartz就把它搞定了。这种延迟(delay)不能叫失火。
然而当,延迟了61秒时misfire handler thread)”就会按照misfire instructions去处理它了。
为了测试效果,这样就能很快的测试“失火”了。
第一个例子triggertrigger调度器是怎么处理“失火”Simple scheduled to run only once:】
1.
val
2.
startAt(DateUtils.addSeconds(
new
Date()10
)).
3.
build()
同样的,但是明确设置了misfire instruction handler(失火处理者):
1.
val
2.
startAt(DateUtils.addSeconds(
new
Date()10
)).
3.
withSchedule(
4.
simpleSchedule().
withMisfireHandlingInstructionFireNow()
//MISFIRE_INSTRUCTION_
6.
).
7.
build()
为了测试trigger设置为10秒前被调度(即当创建后,我们基本上永远不会这么设置。
换句话说trigger,调度器down了或者没有空闲的worker thread了。那么extraordinary(罕见,没有设置misfire instruction(so called smart policy is used in 第二段代码中,我们希望采取的行为。
来看下表:
指令 Instruction | 意义 Meaning | |
smart policy - default | See: withMisfireHandlingInstructionFireNow | |
withMisfireHandlingInstructionFireNow MISFIRE_INSTRUCTION_调度器发现misfire情况后,应用在那段时间由于维护,直到3点才恢复。这样,然后调度器会尝试修复这种情况,尽快执行。 |
||
withMisfireHandlingInstructionIgnoreMisfires MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY |
See: withMisfireHandlingInstructionFireNow | |
withMisfireHandlingInstructionNextWithExistingCount MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT |
See: withMisfireHandlingInstructionNextWithRemainingCount | |
withMisfireHandlingInstructionNextWithRemainingCount MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT |
什么都不做。misfire被忽略了,可以使用这个指令。 例如: ,2个小时候,才发现。 【PS: 这个不是太理解,如果要用withMisfireHandlingInstructionNowWithExistingCount MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT |
See: withMisfireHandlingInstructionFireNow |
withMisfireHandlingInstructionNowWithRemainingCount MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT |
See: withMisfireHandlingInstructionFireNow |
普通,我们有一些需要重复执行指定次数的job:
01.
val
02.
startAt(dateOf(
9
0
0
)).
03.
withSchedule(
04.
simpleSchedule().
0withRepeatCount(
7
).
06.
withIntervalInHours(
1
).
07.
WithMisfireHandlingInstructionFireNow()
//or
other
08.
).
09.
build()
在这个例子中trigger从今天9点开始(startAt(dateOf(9, 0)),和7次重复)。
按理,在9点和10点调度器没有执行job5才被系统发现misfire,调度器会怎么样呢?
指令 Instruction | 意义 Meaning | ||
smart policy - default | See:withMisfireHandlingInstructionNowWithExistingCount | ||
withMisfireHandlingInstructionFireNow MISFIRE_INSTRUCTION_See:withMisfireHandlingInstructionNowWithRemainingCount |
|||
withMisfireHandlingInstructionIgnoreMisfires MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY |
尽快启动所有被启动的,并将调度置为正常。 例如: 在我们上面的例子中,并等待11点时 备注:当处理misfire时,实际job执行的时间,你不能简单地的依赖当前系统时间,而是应该使用 JobExecutionContext .getScheduledFireTime()去获取。 1. def execute(context:
JobExecutionContext) { 2. val
date = context.getScheduledFireTime 3. //... 4. } |
||
withMisfireHandlingInstructionNextWithExistingCount MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT |
调度器不会马上有反应。它会等待下一次执行trigger。 See also: withMisfireHandlingInstructionNextWithRemainingCount 例如: 在10点1,继续执行,共执行8次调度操作withMisfireHandlingInstructionNextWithRemainingCount MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT |
调度器会抛弃被misfire的操作,执行的总次数5,然后继续触发其余的,直到4点。事实上withMisfireHandlingInstructionNowWithExistingCount MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT |
第一次misfire的,而后会按设置的间隔trigger。实际上trigger的第一次触发时间5第一次运行misfire的,然后隔1个小时5执行第二次。共执行8次,在下午5。 |
withMisfireHandlingInstructionNowWithRemainingCount MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT |
第一次misfire的操作,会被抛弃。 剩余没有被misfire的,会按固定间隔被触发。 例如: 调度器会在10点1,它抛弃其余被misfire的(10点那一次)。最后trigger: 11:1,12:15 PM。 |
这是一个基于指定间隔、并重复无数次的
01.
val
02.
startAt(dateOf(
9
0
0
)).
03.
withSchedule(
04.
simpleSchedule().
0withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY).
06.
withIntervalInHours(
1
).
07.
WithMisfireHandlingInstructionFireNow()
//or
other
08.
).
09.
build()
, 0,每隔小时触发一次。然而调度器在9点到10点都没有执行job(比如关闭了系统、线程不够等等。。前面有介绍)5时才被发现trigger更加普遍。
指令 Instruction | 意义 Meaning |
smart policy - default | See:withMisfireHandlingInstructionNowWithExistingCount |
withMisfireHandlingInstructionFireNow MISFIRE_INSTRUCTION_See: withMisfireHandlingInstructionNowWithRemainingCount |
|
withMisfireHandlingInstructionIgnoreMisfires MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY https://jira.terracotta.org/jira/browse/QTZ-283 |
调度器会立即执行所有misfire的,然后继续正常调度。 例如: 9点和10点的,下次执行将按计划执行(下一次是11点执行)。 |
withMisfireHandlingInstructionNextWithExistingCount MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT |
See:withMisfireHandlingInstructionNextWithRemainingCount |
withMisfireHandlingInstructionNextWithRemainingCount MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT |
不做任何事情,调度器按设置的间隔等待下次执行。 例如: 9点和10点misfire的执行被忽略掉。第一次执行会在11点会开始。 Example scenario: Misfired execution at 9 and 10 AM are discarded. The first execution occurs at 11 AM. |
withMisfireHandlingInstructionNowWithExistingCount MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT |
See:withMisfireHandlingInstructionNowWithRemainingCount |
withMisfireHandlingInstructionNowWithRemainingCount MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT |
第一次misfire的执行会被立即运行,就是第一次执行被推迟到了当前时间。 例如: 调度器在10点1trigger,在11点1,执行第二次。以后会每隔一小时。 |
定时触发 CRON 定时触发是Quartz中最常见的。它有另外两个有效的DailyTimeIntervalTrigger(比如每2CalendarIntervalTrigger(比如,但是他们和CRON ,支持同样的misfire
1.
val
2.
withSchedule(
3.
cronSchedule(
"0
0 9-17 ? * MON-FRI"
).
4.
withMisfireHandlingInstructionFireAndProceed()
//or
other
).
6.
build()
这个例子是trigger在每周一到周五的早上9点到下午,每小时被触发一次。但是两次触发被misfire了5时,他们的失火指令效果与普通
指令 Instruction | 意义 Meaning | ||
smart policy - default | See: withMisfireHandlingInstructionFireAndProceed | ||
withMisfireHandlingInstructionIgnoreMisfires MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY https://jira.terracotta.org/jira/browse/QTZ-283 |
所有被misfire的执行会被立即执行trigger。 例如: 9点和10点的执行(misfire的2个)被立即执行withMisfireHandlingInstructionFireAndProceed MISFIRE_INSTRUCTION_ |
立即执行第一次misfire的操作trigger的执行,10点需要执行的那次withMisfireHandlingInstructionDoNothing MISFIRE_INSTRUCTION_DO_NOTHING |
所有被misfire的执行都被忽略掉,好像什么都没发生一样。下次执行将在11点被执行。 |
QTZ-283Note: QTZ-283:
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY not working with JDBCJobStore - apparently there is a bug when JDBCJobStore is
usedthat issue. (在用JDBCJobStore 时MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY 没有生效。显然JDBCJobStore时的一个bug
如你所有,不同的,虽然它提供了smart policy(明智的决策),还是要取决于业务需求。
从本质上看,立即运行然后继续正常执行ignorerun immediately and continue and discard and wait for next. )
它们有不同的应用场景:
当你需要确保每次调度任务都要被执行的时候trigger会被触发ignore policies。试想一下,需要每小时,那你可能仍然是尽快得到那些报表的。这种情况下ignore policies,但是仍然是被执行了(最终报告到手了。^_^)。
当你需要任务被定期执行,那么使用now* policies。试想一下,最后终于可以执行这个任务了,但是要尽快执行。而后,使用next* policies不错。比如你需要在每个整点后1,然后现在已经整点后20分了5分钟,一个时间间隙总好过一个不准确的值。这种情况Quartz只要跳过misfire的操作,等待下次执行就好了。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何给本地部署的DeepSeek投喂数据,让他更懂你
· 李飞飞的50美金比肩DeepSeek把CEO忽悠瘸了,倒霉的却是程序员
· 超详细,DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方Dee
· 用 DeepSeek 给对象做个网站,她一定感动坏了
· .NET 8.0 + Linux 香橙派,实现高效的 IoT 数据采集与控制解决方案