如果你在用quartz的时候,也看到这个日志信息(Handling 2 trigger(s) that missed their scheduled fire-time.)了,并且发现quartz管理的任务,都不再被触发了,那么,你可以看看这篇文章。
m6 h9 n* N, [* z( i2 C& o$ F) S; y) g& W
原文地址:
http://java.dzone.com/articles/quartz-scheduler-misfire% G4 \4 D" a) |! d$ F; _" o
由于本人英文水平有限,部分地方会直接用原文英语代替,另,部分翻译可能比较晦涩,望理解。
1 `1 `6 z2 A/ U1 V
. R) |7 z! u' {, i( A常见词:
5 e1 N: w. }: t, r( a7 _# C% ?. T
misfire
http://fanyi.baidu.com/#en/zh/misfire 以下统一用misfire,汉语无法贴切表达
) F3 N$ n5 V m% @misfire instruction 失火(没启动起来后的)指示
( }( ~. C8 H; ]smart policy,明智的决策
9 h# P4 _: d) i8 Q
misfired 失火了,没启动起来的意思
3 X. a+ \' `, Z/ {& iworker thread 工作线程,辅助线程
4 W k. ^! t7 }- |8 I: ?0 M
# E& H( H b- S6 j. ~
【翻译】
% I" Y+ b9 j2 B. M. j9 d有时候,Quartz并不能如你所愿的运行你的job。这里有3个原因:
( e7 N: S: r+ G/ l( i: y
1.所有的woker thread(工作线程; 辅助线程)都在运行其他的job
; N9 m# s4 o& @2.scheduler(调度器)down了(关于这个down。我不太明确是shutdown了。。还是挂掉了。因此下文依旧用down。)
5 o% N, p4 Y, s0 | B9 s3.任务被安排在过去的某一时刻启动(此可能为代码错误)
5 l& d2 s; |. F( J8 h6 ], M) K1 D; w7 H# b
你可以简单地通过配置quartz.properties文件中的org.quartz.threadPool.threadCount,来增加worker thread的数量(默认为10)。但是当整个 applicationfile:///C:\Users\user\AppData\Local\Temp\V7(XMWRN]{G8~CI}BCCR3QC.gifrver/scheduler (调度器)挂掉的时候,这方法仍然是无效的。这种Quartz无法启动指定触发器情况,叫做 misfire(
http://fanyi.baidu.com/#en/zh/misfire 以下统一用misfire,汉语无法贴切表达)。
z3 y$ `- M$ t+ {( r
你知道当这种情况发生的时候,Quartz能做些什么吗? 其实,Quartz有许多的策略(叫misfire instructions,失火指示)可以处理问题,并且当你没有去想这方面问题的时候,它也有许多默认策略。但是为了使你的应用更加稳定和可预测(尤其是在高负载和可维护性上),你应该有意识的去确保triggers 和 jobs工作正常。
: v& O% C/ R5 ?% Y2 [$ V基于你用的trigger,会有不同的配置选项(对misfire instructions有效)。当然,不同的trigger也会使Quartz有不同的行为(叫做smart policy,明智的决策)。尽管文档中有misfire instructions的描述,但是我发现都很难理解它所想表达的意思,因此,我写下这篇简短的总结。
: D0 C3 z( m. b# Q
在我深入细节之前,还有一个配置需要说明下:org.quartz.jobStore.misfireThreshold(毫秒级),默认是60000(一分钟)。它定义了trigger被认为是misfired了的时限。
" f$ Y. p6 ]9 K) c4 Y/ _8 l- ~基于默认配置,如果trigger应该在30秒以前被触发,那么很愉快地,Quartz就把它搞定了。这种延迟(delay)不能叫失火。
5 `- c8 ?2 c8 f/ V0 T1 f然而当trigger被发现,延迟了61秒时,那么专门的“失火处理者(misfire handler thread)”就会按照misfire instructions去处理它了。
# m# z! a& b- F- {3 k为了测试效果,我们将这个时间设置为1000(即1秒),这样就能很快的测试“失火”了。
6 ^& D& O1 z, z; b C
6 B- {3 K/ H. k
# Z6 {, y( {1 X u第一个例子,是一个不需要重复触发的普通trigger,我们来看看普通trigger调度器是怎么处理“失火”,并让它运行一次的:
' _5 V1 w* n# M' z6 `8 Q
【原文:Simple trigger without repeating In our first example we will see how misfiring is handled by simple triggers scheduled to run only once:】
$ ^; R7 I( @) q- m
view sourceprint?
& g! u$ A3 O- b1 N) u ~
1.val trigger = newTrigger().
/ |4 U+ ^9 I7 O3 c# d
2.startAt(DateUtils.addSeconds(new Date(), -10)).
% D3 x7 ~$ D! B9 S( t7 ]: J3.build()
* T1 a+ N4 D) ^6 \6 j( c5 B2 ?, c3 H" c: k) \+ }6 W
& ~, n5 |' o& A- t) _6 T" e. Y5 J同样的trigger,但是明确设置了misfire instruction handler(失火处理者):
; ]* h& Q3 Q, [view sourceprint?
5 R! m: A% a$ w# `: Y) C- s0 ?
1.val trigger = newTrigger().
: h2 P+ T! L# O2.startAt(DateUtils.addSeconds(new Date(), -10)).
& i L# T9 g5 Y/ o/ a4 i0 S3.withSchedule(
u% K, T8 n& f9 {% L9 e D4.simpleSchedule().
4 a7 Y" ^. c% ]# n- j4 Q/ V5.withMisfireHandlingInstructionFireNow() //MISFIRE_INSTRUCTION_FIRE_NOW
/ ~3 _0 D2 u9 U# G J6 ~6.).
4 Q) M* H# D; v& n) A
7.build()
% C5 ~, @2 n. p w% b1 E- V/ [. Q0 W4 _3 z, z# f% K9 _* ^* n
* ~& w/ _! L2 v+ U$ g. z9 K! T为了测试,我将trigger设置为10秒前被调度(即当创建后,就已经晚于启动时间10秒)。在实际使用时,我们基本上永远不会这么设置。
5 j& T9 H; h# X4 ~" s换句话说,如果我们正确的设置了trigger,但是当需要被调度的时候,调度器down了或者没有空闲的worker thread了。那么,Quartz怎么处理这种extraordinary(罕见,古怪)的情况呢?
# o' m9 [: l- {0 u+ Q# x1 m) b
在第一段代码中,没有设置misfire instruction(so called smart policy is used in that case 这句不太会翻译。。。。)。
9 x) ^9 Z8 O0 T- w, g$ { u
第二段代码中,明确指定了当misfire发生时,我们希望采取的行为。
* }3 E1 A. C9 ?1 x) o; R: D
来看下表:
' S$ c/ e; r, L" J9 k4 _' t" |
) y* `- m- ]9 e X! U& W1 [/ ^1 O- y0 Q
指令 Instruction 意义 Meaning
3 P- w$ E8 a# z2 P: S3 E) osmart policy - default See: withMisfireHandlingInstructionFireNow
- ?% l' ~, D% i Q9 u
withMisfireHandlingInstructionFireNow
) E2 n4 D6 T; t5 k/ n) v0 TMISFIRE_INSTRUCTION_FIRE_NOW 调度器发现misfire情况后,立即执行job。
3 d% Q) ^, Y# q m$ T% k
这是smart policy。
5 O- J: D4 b, y0 M9 L- e# c5 z
例如:
$ u2 u+ r4 U6 _# A; ?( H* G2 s你让一些系统清理功能在2点执行。但是很不幸,应用在那段时间由于维护,关闭了,直到3点才恢复。这样trigger就misfire了,然后调度器会尝试修复这种情况,在3点启动后,尽快执行。
0 l, k/ f4 h) f: L P9 CwithMisfireHandlingInstructionIgnoreMisfires
) W$ ]( J9 w9 n* Z6 P* j5 j6 xMISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY See: withMisfireHandlingInstructionFireNow
: O) `+ y! O0 l5 V7 @4 l
withMisfireHandlingInstructionNextWithExistingCount
* n8 H/ _, r- G3 I" DMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT See: withMisfireHandlingInstructionNextWithRemainingCount
" E8 I8 q* S& [withMisfireHandlingInstructionNextWithRemainingCount
& A* \% Y7 d! e5 z# g0 h& d
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 什么都不做。misfire被忽略了,并且没有后续的执行。当你想要彻底放弃被misfire的执行时,可以使用这个指令。
4 g6 K3 E' t: v M. k8 R例如:
N0 G v: s. [% \; q% ytrigger是要启动录制一个电视节目。但是被misfire了,2个小时候,才发现。
: V4 }; j' R; U4 S* b【PS: 这个不是太理解,只是按照原文翻译过来,如果要用,请自行测试。。。】
+ N4 d; M4 T; I0 {5 MwithMisfireHandlingInstructionNowWithExistingCount
Z3 }: r) ^/ z2 h. R, ~$ GMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT See: withMisfireHandlingInstructionFireNow
0 S8 G; u) B4 U4 U2 f
withMisfireHandlingInstructionNowWithRemainingCount
" Q; w7 p: t0 m, `; s% D
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT See: withMisfireHandlingInstructionFireNow
- @& @" b( \1 w% K0 Q2 }7 L) t0 k) A6 ]+ l3 d7 D* J( N
2 P1 M" z6 b1 ~& D6 p8 \, Y: Y
普通trigger重复执行指定次数。这种情形更加复杂。想象一下,我们有一些需要重复执行指定次数的job:
0 h+ b: A6 \6 h2 c
view sourceprint?
" `2 U' W% R! z1 K# b; e01.val trigger = newTrigger().
2 M2 |$ C( j7 w8 m' {. U) i02.startAt(dateOf(9, 0, 0)).
( n5 e; T7 C0 q
03.withSchedule(
2 A. R# |8 l$ {- A04.simpleSchedule().
& P9 b5 L S2 n9 H: _# \ ~! q2 {05.withRepeatCount(7).
3 q2 K( {4 \' H1 H06.withIntervalInHours(1).
" O0 P: j( U5 s07.WithMisfireHandlingInstructionFireNow() //or other
% V! ]4 Q8 W& p. E: ?7 H
08.).
8 B* X6 d7 j3 ?3 E09.build()
# A; E. y: q( y0 W' }; E f
6 H+ `" N- N. K
# h/ e9 D6 p5 c" h/ L7 h在这个例子中,trigger从今天9点开始(startAt(dateOf(9, 0, 0)),共触发8次(第一次执行,和7次重复)。
* v" d' K. i U7 m k4 @按理,最后一次执行应该在下午4点被触发。假设由于某些原因,在9点和10点调度器没有执行job,并且直到10:15才被系统发现misfire,也就是misfire了2次。这种情况下,调度器会怎么样呢?
/ @: G; W8 t/ V( c+ o0 _
指令 Instruction 意义 Meaning
: v, ^9 i& B; O! R" \9 T2 Z. `smart policy - default See:withMisfireHandlingInstructionNowWithExistingCount
3 p* e8 c, M3 |. @! x7 v
withMisfireHandlingInstructionFireNow
7 E$ k/ s, A/ k
MISFIRE_INSTRUCTION_FIRE_NOW See:withMisfireHandlingInstructionNowWithRemainingCount
$ {! p1 L5 j3 @0 D( n# T4 AwithMisfireHandlingInstructionIgnoreMisfires
8 V( i% H) j3 q! H# J6 q* K" r
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY 尽快启动所有被启动的trigger,并将调度置为正常。
& ?! L& Q! ?7 a$ c2 r例如:
: Y" [ }- g4 s; P- e% W
在我们上面的例子中,调度器会立即执行9点和10点的任务,并等待11点时,继续按正常的调度执行。
2 e$ L8 e/ @, R1 \" R/ }8 I
备注:当处理misfire时,我们同样要注意到,实际job执行的时间,已经滞后于应该执行的时间。这意味着,你不能简单地的依赖当前系统时间,而是应该使用 JobExecutionContext .getScheduledFireTime()去获取。
, C4 w+ f: s+ H, e2 tview sourceprint?
9 P" o" v: P+ ?- t6 U* O# A( D1.def execute(context: JobExecutionContext) {
0 ?/ k* ]' ?6 t( w; O( T9 {
2.val date = context.getScheduledFireTime
: M* \6 R% D- J3 {& z: p) x6 n3.//...
5 s& _; Q: k9 L" u- w
4.}
- S7 u# ~$ q1 y$ S# O7 P4 F7 G
U( \; B& e5 [2 i: k! O
; p5 _6 O9 ]6 h5 M2 V5 r7 BwithMisfireHandlingInstructionNextWithExistingCount
2 l: c, ]/ U) W
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT 调度器不会马上有反应。它会等待下一次执行,然后根据应该调度次数去运行trigger。
" M' T/ U/ a+ I. Y$ nSee also: withMisfireHandlingInstructionNextWithRemainingCount
2 q9 c5 r i/ y) c- s, @3 O/ g% O% k
例如:
, W0 v0 ?' |- ?) t9 E在10点15发现2次misfire。调度器会等到11点,继续执行,并会每小时执行1次,共执行8次调度操作,直到下午6点停止(本该4点停止的。)
9 s! i4 y( b! t4 O' \4 x7 kwithMisfireHandlingInstructionNextWithRemainingCount
" D1 V, V! \, b$ t$ g0 nMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 调度器会抛弃被misfire的操作,然后等待下次执行。这样,执行的总次数,就会小于配置的次数。
9 E+ X1 A* ~9 [$ f5 f. G8 ]例如:在10点15,2次misfire的执行都被丢弃了。调度器会等到下个执行时间-11点,然后继续触发其余的trigger,直到4点。事实上,这种情况就像misfire从未发生过一样。
: n8 W8 O/ O3 J4 C0 QwithMisfireHandlingInstructionNowWithExistingCount
* w$ `7 ?% G, ]6 r) K7 Z
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
9 {1 g, [1 S$ T, A& J5 W6 m第一次misfire的trigger会立即执行,而后会按设置的间隔,依次执行剩余的trigger。实际上,就像misfire的trigger的第一次触发时间,被平移到了当前时间。
7 ^0 j% L) n* J3 \例如:
9 X, [8 C6 l( p6 M7 y o4 y
调度器会在10点15第一次运行misfire的trigger,然后隔1个小时,在11点15执行第二次。共执行8次,最后一次,在下午5点15。
8 ]# O0 i- l' Z2 X' [6 o9 Y7 J+ n, K$ ~( g
withMisfireHandlingInstructionNowWithRemainingCount
( _' R* g- l) ?* WMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
' b8 E6 P; U0 B# p! W第一次misfire的操作,被立即执行。其余被misfire的操作,会被抛弃。
J" Z' g& Z X; m
剩余没有被misfire的trigger,会按固定间隔被触发。
2 y5 A6 s1 v9 {$ z9 k
例如:
' e$ M4 c5 @ `1 O- T3 b4 M
调度器会在10点15运行第一次被misfire的操作(9点的。)。然后,它抛弃其余被misfire的(10点那一次)。最后,它会等1小时继续触发6个trigger:
; F9 K& i: X4 \9 a
11:15,12:15.... 4:15 PM。
7 n% J4 V/ t: m; N+ \# t
1 R4 S, [" w& H8 r* d
( U/ m% \" } e+ C这是一个基于指定间隔、并重复无数次的trigger:
% I. z' S7 j ^view sourceprint?
4 d, v5 n2 }; c( h( H7 x01.val trigger = newTrigger().
7 u5 S0 M# }) E' K# O( O/ c02.startAt(dateOf(9, 0, 0)).
9 f3 D% d$ B( K$ w! i: t03.withSchedule(
( {, R9 [ G# a04.simpleSchedule().
' b/ I+ y1 d. `$ g05.withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY).
! ?, S% ]( J4 i$ Z/ R. Y" @
06.withIntervalInHours(1).
- ?/ P6 V9 B# I0 Y9 m6 k& S6 ^07.WithMisfireHandlingInstructionFireNow() //or other
" P6 y4 w+ t, k+ J: K1 r08.).
; l, ]; _3 V; r e3 p
09.build()
/ o+ k9 j: Z+ [
! F9 k) {: H. F+ Q' ]# Q( t# D+ d a! ^6 W* H
trigger应该从今天9点开始(startAt(dateOf(9, 0, 0)),每隔小时触发一次。然而调度器在9点到10点都没有执行job(比如关闭了系统、线程不够等等。。前面有介绍),并且在10点15时才被发现,misfire了2次。这种情况比那种执行执行次数的trigger更加普遍。
4 U$ k4 w+ e" q5 I指令 Instruction 意义 Meaning
; c; I, u5 f5 D B1 u
smart policy - default See:withMisfireHandlingInstructionNowWithExistingCount
# U$ T9 K3 E/ _; r, S
withMisfireHandlingInstructionFireNow
$ P5 I, l ^1 I$ Q% v/ J9 w6 g
MISFIRE_INSTRUCTION_FIRE_NOW See: withMisfireHandlingInstructionNowWithRemainingCount
8 g" j' `) c1 u- D5 IwithMisfireHandlingInstructionIgnoreMisfires
+ p2 }& h2 ^2 T
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
$ b. }4 J. G+ |# |8 e: h9 t
https://jira.terracotta.org/jira/browse/QTZ-283( F5 c p' l* D6 S! s
调度器会立即执行所有misfire的trigger,然后继续正常调度。
1 x C. \; J) R/ f ^) B例如:
) R0 o& E# K% K% c2 w& u- ^9点和10点的trigger会立即执行,下次执行将按计划执行(下一次是11点执行)。
( j* j c; m# S/ W* _% M l! E
9 I' n# P) T( R( A' q& ^+ k! KwithMisfireHandlingInstructionNextWithExistingCount
: F4 X; M- h2 |% o9 P6 ^MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT See:withMisfireHandlingInstructionNextWithRemainingCount
, s8 O# d' [/ M( b
withMisfireHandlingInstructionNextWithRemainingCount
. P0 l" ?& }: M+ Q
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
" b9 ?1 j% `9 ]' A不做任何事情,misfire的情况被忽略掉。然后,调度器按设置的间隔等待下次执行。
$ Q) L$ K# A. L例如:
, s' t; d( G/ {7 ]2 u' j0 w: b
9点和10点misfire的执行被忽略掉。第一次执行会在11点会开始。
# v" p/ r0 O8 v1 y0 ~6 bExample scenario: Misfired execution at 9 and 10 AM are discarded. The first execution occurs at 11 AM.
4 t7 ?: ^5 c0 G; L
: D7 o- u6 d& k; O" }' P" `3 h, e
withMisfireHandlingInstructionNowWithExistingCount
8 ]0 {! K- o: c& u& `; e4 QMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
" w: c7 f7 }" {8 b- M" ~
See:withMisfireHandlingInstructionNowWithRemainingCount
: k1 A5 e- q7 a) u9 k
withMisfireHandlingInstructionNowWithRemainingCount
' {$ X4 V9 F; X- c# J; i5 CMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
2 [# R1 E0 G1 B) c
7 s) g. E1 H0 _1 Y7 m
) L3 P- ?! P0 F- l, y: c5 u4 j第一次misfire的执行会被立即运行,其余的被忽略。下次执行会在设置的间隔时间后被触发。实际上,就是第一次执行被推迟到了当前时间。
" H, F$ @+ K, u- ^6 j3 M
例如:
( _9 z% m$ n2 h2 ^% W! |
调度器在10点15立即执行misfire的trigger,然后等待一个小时后,在11点15时,执行第二次。以后会每隔一小时。
3 ^4 C! U$ U! t6 J, f9 R8 m6 Q
, u z( _7 X7 V$ Y8 V3 F5 [7 D% ?! x1 Q6 W; D8 I2 L5 l a$ l
定时触发 CRON trigger
# r* T( o6 w1 N) C; T# F定时触发是Quartz中最常见的。它有另外两个有效的trigger:DailyTimeIntervalTrigger(比如每25分钟一次)和CalendarIntervalTrigger(比如5个月执行一次)。They support triggering policies not possible in both CRON and simple triggers.(不会译- -!),但是他们和CRON trigger一样,支持同样的misfire handling instructions(失火处理指令)。
3 g6 z; X' @# D+ d3 O3 g* nview sourceprint?
$ }8 q+ c1 F7 \7 Z1.val trigger = newTrigger().
5 N/ H p% L8 z( Z5 F" |& P% S2.withSchedule(
3 _$ j" L9 X. I
3.cronSchedule("0 0 9-17 ? * MON-FRI").
0 _8 x2 t4 s$ d, v4.withMisfireHandlingInstructionFireAndProceed() //or other
8 J6 O6 e' Z8 `# H' z7 a8 R1 E# b5.).
( @* k6 j/ V( ?5 T( U( Y% D6.build()
8 f& V e7 J$ G$ `
& Z# ~. M( H$ M# e% m5 S
- z4 Q6 }3 Y, g; w这个例子是,trigger在每周一到周五的早上9点到下午5点间,每小时被触发一次。但是两次触发被misfire了,并且在10点15时,才发现这个情况。请注意,他们的失火指令效果与普通trigger是不同的:
7 d$ v8 ^: c- Q+ x) J4 P- ?# ~指令 Instruction 意义 Meaning
8 a7 Y6 q! h& }, r: V! Vsmart policy - default See: withMisfireHandlingInstructionFireAndProceed
9 J A0 G8 B9 s' Y
withMisfireHandlingInstructionIgnoreMisfires
0 _8 Y3 V1 u* f
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
# x1 }$ i& f( `https://jira.terracotta.org/jira/browse/QTZ-2832 S% K( L$ u3 A/ L# k0 i
所有被misfire的执行会被立即执行,然后按照正常调度继续执行trigger。
# |1 y; k# U& p# u. w- J. q例如:
+ h! {; S+ l7 U$ C% D& Z; `. c: L9点和10点的执行(misfire的2个)被立即执行,下次执行将在11点被准时执行。
" p7 k( k/ I- |: z
withMisfireHandlingInstructionFireAndProceed
& ~# N( J- M" N+ |* ^. q
MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
( J+ o" F9 D7 g1 ?立即执行第一次misfire的操作,并且放弃其他misfire的(类似所有misfire的操作被合并执行了)。然后继续按调度执行。无论misfire多少次trigger的执行,都只会立刻执行1次。
# d b4 Q! g) _) Q4 z例如:
" k& Q3 F5 f+ X8 o' Q9点和10点的被合并执行一次(换句话说,10点需要执行的那次,被pass了)。下次执行将在11点被准时执行。
) q1 t8 u1 J# s6 V9 k& h
withMisfireHandlingInstructionDoNothing
1 B1 |# f9 v+ }0 \3 _
MISFIRE_INSTRUCTION_DO_NOTHING
( W5 v6 }' I$ ]0 q. {$ n5 V所有被misfire的执行都被忽略掉,调度器会像平时一样等待下次调度。
% q$ e, ~ W& ?4 o
例如:
# c' n0 I& N+ b: W F2 @9点和10点的被忽略掉,好像什么都没发生一样。下次执行将在11点被执行。
# j9 r# i5 a9 j/ o9 Q
' F9 |4 `' r! H- L
QTZ-283Note: QTZ-283: MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY not working with JDBCJobStore - apparently there is a bug when JDBCJobStore is used, keep an eye on that issue. (在用JDBCJobStore 时,MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY 没有生效。显然,这是在使用JDBCJobStore时的一个bug,关注下。)
! j% b8 c2 M3 ?& E- r& }8 v$ d5 i3 r. y" g! H# o8 S
如你所有,根据实际的设定,不同的trigger会有不同的行为。此外,虽然它提供了smart policy(明智的决策),但是真正使用时,还是要取决于业务需求。
( ^9 P9 T. G0 A* M0 K从本质上看,主要有三种策略:忽略,立即运行然后继续正常执行,忽略misfire的并等待下次执行。( 原文: ignore, run immediately and continue and discard and wait for next. )
; M- i) E0 Y, ^( Q2 b/ @它们有不同的应用场景:
8 k7 ?+ O- P' C4 f$ k. e
当你需要确保每次调度任务都要被执行的时候,即时它意味着多个misfire的trigger会被触发,那么用ignore policies。试想一下,有一个任务,需要每小时,都根据上一小时的订单去生成报表。如果服务被关闭了8个小时,那你可能仍然是尽快得到那些报表的。这种情况下,配置ignore policies,调度器会尽快将那8小时的调度任务运行一遍的。尽管晚了几个小时,但是仍然是被执行了(最终报告到手了。^_^)。
4 U# V5 W8 {: G1 q: H
当你需要任务被定期执行,并且当出现misfire的情况后立即运行一次的时候,那么使用now* policies。试想一下,一个任务是每分钟清空文件夹 /tmp。如果调度器在20分钟内繁忙,最后终于可以执行这个任务了,那么你肯定不会希望它执行20次的!一次就足够了,但是要尽快执行。而后,再回到正常的执行间隔--1分钟。
+ e, h' i2 C+ [3 a3 s+ b5 q+ x) |
当你希望任务能在特定时间点运行的时候,使用next* policies不错。比如你需要在每个整点后15分钟抓取股票的价格。它们的变化非常快,然后现在已经整点后20分了,那么不必烦恼。你刚好错过了5分钟,但是现在你已经不在乎(那时候的价格)了。这时,一个时间间隙总好过一个不准确的值。这种情况Quartz只要跳过misfire的操作,等待下次执行就好了。
% `+ e' M X6 t0 q# P% p7 W! N9 P% M& U* \# I: b
(此文仅为作者观点,我在翻译过程中,其实也有不太明了之处,但是总体来说,还是清晰的,希望大家在以后使用工具时,也更多的关注工具的一切内在功能。)
5 ^) d# H# n3 Q, t; D2 V, c4 N! N& M4 t6 e9 S0 q' w3 V
( ^' [6 U; q- }9 ?! A7 B i" B. P
再次注明,原文地址:
http://java.dzone.com/articles/quartz-scheduler-misfire
* {! F2 E6 _* o$ x' C: {如转,请尊重原作者,贴上链接。
7 F$ _; ]6 M: J6 @: }* C
5 H, a0 K" x5 D