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(900)).
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(900)).
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-283NoteQTZ-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的操作等待下次执行就好了。

posted @ 2022-01-21 07:25  锐洋智能  阅读(806)  评论(0编辑  收藏  举报