如果你在用quartz的时候,也看到这个日志信息(Handling 2 trigger(s) that missed their scheduled fire-time.)了,并且发现quartz管理的任务,都不再被触发了,那么,你可以看看这篇文章。
; ^4 n1 g3 E7 I: l* r9 t
1 y" q$ `7 ]( g9 }& |$ h
原文地址:
http://java.dzone.com/articles/quartz-scheduler-misfire
$ u- e: X* e0 I# a: G由于本人英文水平有限,部分地方会直接用原文英语代替,另,部分翻译可能比较晦涩,望理解。
% `4 i) N. G/ o: s& n5 l
+ L3 g+ s! f6 c0 w常见词:
8 t/ l& M; O) z) M) x- Y& V: c _: v) w
misfire
http://fanyi.baidu.com/#en/zh/misfire 以下统一用misfire,汉语无法贴切表达
2 K& Y U9 c1 k% t6 w+ V$ g
misfire instruction 失火(没启动起来后的)指示
5 y2 u' q0 n. g( hsmart policy,明智的决策
; v0 |3 O3 o4 l4 m, y6 e, [; E' lmisfired 失火了,没启动起来的意思
! p/ Q) x ]8 n6 j5 a
worker thread 工作线程,辅助线程
* [$ P7 E. E3 p( K9 n- B2 _
8 E$ i$ Z& q# o: E4 H4 t【翻译】
4 r5 E9 {# q) \6 k- k9 Z* w! w0 |有时候,Quartz并不能如你所愿的运行你的job。这里有3个原因:
: z3 ?; H( L' j) f/ l1 B% h1.所有的woker thread(工作线程; 辅助线程)都在运行其他的job
- ]) C) S) Q- y/ V
2.scheduler(调度器)down了(关于这个down。我不太明确是shutdown了。。还是挂掉了。因此下文依旧用down。)
; W% v: F. H U2 ^3 u; W* v3.任务被安排在过去的某一时刻启动(此可能为代码错误)
0 d7 E8 r' T: b: O
% v; u T) R8 W$ U" \: l你可以简单地通过配置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,汉语无法贴切表达)。
) E8 r, z8 c# p& h7 K+ Z
你知道当这种情况发生的时候,Quartz能做些什么吗? 其实,Quartz有许多的策略(叫misfire instructions,失火指示)可以处理问题,并且当你没有去想这方面问题的时候,它也有许多默认策略。但是为了使你的应用更加稳定和可预测(尤其是在高负载和可维护性上),你应该有意识的去确保triggers 和 jobs工作正常。
" d% c0 p& j& S% B- A* u% j
基于你用的trigger,会有不同的配置选项(对misfire instructions有效)。当然,不同的trigger也会使Quartz有不同的行为(叫做smart policy,明智的决策)。尽管文档中有misfire instructions的描述,但是我发现都很难理解它所想表达的意思,因此,我写下这篇简短的总结。
9 s% y: f( A# u/ ^( f在我深入细节之前,还有一个配置需要说明下:org.quartz.jobStore.misfireThreshold(毫秒级),默认是60000(一分钟)。它定义了trigger被认为是misfired了的时限。
8 e- L9 J* T7 c3 G2 u' z+ D6 v' Z基于默认配置,如果trigger应该在30秒以前被触发,那么很愉快地,Quartz就把它搞定了。这种延迟(delay)不能叫失火。
+ B. y1 m; g% o" b然而当trigger被发现,延迟了61秒时,那么专门的“失火处理者(misfire handler thread)”就会按照misfire instructions去处理它了。
+ y& P8 U- I8 Y+ \8 ~$ R- |- \6 z
为了测试效果,我们将这个时间设置为1000(即1秒),这样就能很快的测试“失火”了。
4 r) D1 c( _6 s) F/ o5 I: C: w
8 `: Y) [% n) V0 a4 `: C$ @. v
; {+ ]) u( @' V, g$ s第一个例子,是一个不需要重复触发的普通trigger,我们来看看普通trigger调度器是怎么处理“失火”,并让它运行一次的:
% j7 t2 P$ r7 z, ^【原文:Simple trigger without repeating In our first example we will see how misfiring is handled by simple triggers scheduled to run only once:】
0 @% x# O4 q3 `
view sourceprint?
+ a( B$ `. J7 [2 v6 X1.val trigger = newTrigger().
; v0 o+ R. D* r6 d" V/ B/ l
2.startAt(DateUtils.addSeconds(new Date(), -10)).
4 U* I% ~: s: G2 ]. b
3.build()
* O2 A6 a) Q0 @. @7 \
0 g2 g: g3 }7 o2 [& A8 ~2 Y! h- y3 g7 x2 t, h' \+ b0 L* \* N
同样的trigger,但是明确设置了misfire instruction handler(失火处理者):
2 [7 @" \$ D6 ?6 \2 \
view sourceprint?
9 y6 ~3 k8 a1 K, w" X- N3 L- G1.val trigger = newTrigger().
" J1 I/ N6 j- u( @# e- E8 G
2.startAt(DateUtils.addSeconds(new Date(), -10)).
# r6 q( E4 B m. t" P; h3.withSchedule(
" ~% L1 t( ~8 b4 n7 U. Z
4.simpleSchedule().
1 ~4 Q( H' }, E" V( j- d# f8 j5.withMisfireHandlingInstructionFireNow() //MISFIRE_INSTRUCTION_FIRE_NOW
& L. }& c( `3 t; H6.).
9 d+ f* a# E {: C- P) G7.build()
/ p5 I5 a" P. S( U! k% ?
- P9 }0 @' `/ C: F8 m( K% E2 Y3 m$ P
为了测试,我将trigger设置为10秒前被调度(即当创建后,就已经晚于启动时间10秒)。在实际使用时,我们基本上永远不会这么设置。
1 V% ~: h e4 Q+ z3 c A7 K换句话说,如果我们正确的设置了trigger,但是当需要被调度的时候,调度器down了或者没有空闲的worker thread了。那么,Quartz怎么处理这种extraordinary(罕见,古怪)的情况呢?
6 W! m: G( n, D% r+ n( E4 t1 M! F6 J8 O
在第一段代码中,没有设置misfire instruction(so called smart policy is used in that case 这句不太会翻译。。。。)。
2 Z% b a( \& C) f: u5 j
第二段代码中,明确指定了当misfire发生时,我们希望采取的行为。
( J* P: i4 m1 R$ }( }0 b来看下表:
4 {2 E# Y7 L7 h6 X, Y/ y
3 ]6 O' E2 A* a; Z1 ]6 {, Q" a
指令 Instruction 意义 Meaning
* W+ l: Y# K1 t1 L0 hsmart policy - default See: withMisfireHandlingInstructionFireNow
2 f% l7 A- o& M2 G5 V9 rwithMisfireHandlingInstructionFireNow
' F3 T9 y$ b! f$ z: d% A6 J
MISFIRE_INSTRUCTION_FIRE_NOW 调度器发现misfire情况后,立即执行job。
2 a: w3 B. c% }* ]. |这是smart policy。
2 _- u/ S/ |+ ?8 A! R: S. j例如:
) t) I$ U4 |$ v/ a9 L- P你让一些系统清理功能在2点执行。但是很不幸,应用在那段时间由于维护,关闭了,直到3点才恢复。这样trigger就misfire了,然后调度器会尝试修复这种情况,在3点启动后,尽快执行。
4 Y1 Z4 X* Y3 s$ s7 S
withMisfireHandlingInstructionIgnoreMisfires
; `, R; l4 N: o1 ~MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY See: withMisfireHandlingInstructionFireNow
G% H2 z* C, Z( S0 I
withMisfireHandlingInstructionNextWithExistingCount
- b+ g4 D% c+ ?: x+ S Y
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT See: withMisfireHandlingInstructionNextWithRemainingCount
1 T' U" b, ?" E& d1 A! VwithMisfireHandlingInstructionNextWithRemainingCount
1 d1 K7 s, N( n& A/ QMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 什么都不做。misfire被忽略了,并且没有后续的执行。当你想要彻底放弃被misfire的执行时,可以使用这个指令。
+ R" b+ H4 \; q% n2 u) z
例如:
8 L n% ]8 H* a* p
trigger是要启动录制一个电视节目。但是被misfire了,2个小时候,才发现。
5 }& _) n1 N+ }1 r
【PS: 这个不是太理解,只是按照原文翻译过来,如果要用,请自行测试。。。】
; i2 }9 Z% z1 Z& o' R& ?; w3 p
withMisfireHandlingInstructionNowWithExistingCount
: @; v" O, U* P7 L3 V7 Z6 a6 E
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT See: withMisfireHandlingInstructionFireNow
% J4 ]$ {4 X' O/ EwithMisfireHandlingInstructionNowWithRemainingCount
: K5 a3 C4 f8 R$ a9 ^MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT See: withMisfireHandlingInstructionFireNow
# Z2 z2 c: L5 ]2 ?" u7 {, ^- L* M h9 _* p" I% P v+ y, o8 {
1 H6 j f$ B( ~9 r9 l7 Q
普通trigger重复执行指定次数。这种情形更加复杂。想象一下,我们有一些需要重复执行指定次数的job:
& r! U' M! Z. X7 tview sourceprint?
' v8 c, \& r* c8 c w: c01.val trigger = newTrigger().
3 v' M5 \$ S" s, [' u
02.startAt(dateOf(9, 0, 0)).
* w6 O" q* [4 o9 K4 x, T s
03.withSchedule(
4 {: X( p4 c9 [! ?" m5 E
04.simpleSchedule().
W$ P [5 ] p1 }
05.withRepeatCount(7).
! Y; B9 y& s# R& Q8 T4 |' H/ j$ c
06.withIntervalInHours(1).
# l1 P) x, J: |( m J3 b07.WithMisfireHandlingInstructionFireNow() //or other
& v& e% g F4 _8 T- b% p( d08.).
! Y0 R$ C; C+ @4 k; q09.build()
$ N `, H; } L8 c3 h
: h! U5 l6 Y9 ^' g0 P8 H' C; o3 T$ t- f2 E! j# ~/ X
在这个例子中,trigger从今天9点开始(startAt(dateOf(9, 0, 0)),共触发8次(第一次执行,和7次重复)。
0 n6 W1 c1 _- h- Q
按理,最后一次执行应该在下午4点被触发。假设由于某些原因,在9点和10点调度器没有执行job,并且直到10:15才被系统发现misfire,也就是misfire了2次。这种情况下,调度器会怎么样呢?
# _' Y! m# ~4 S5 p6 D& {
指令 Instruction 意义 Meaning
7 r2 X7 C) M0 Q8 x6 k& X8 {
smart policy - default See:withMisfireHandlingInstructionNowWithExistingCount
0 S) Z5 C L4 BwithMisfireHandlingInstructionFireNow
+ S5 ^' f( p9 Y0 iMISFIRE_INSTRUCTION_FIRE_NOW See:withMisfireHandlingInstructionNowWithRemainingCount
# i5 \; `8 i U+ ^( O9 }withMisfireHandlingInstructionIgnoreMisfires
* C; p* y0 c; h J
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY 尽快启动所有被启动的trigger,并将调度置为正常。
; R' i4 F/ B9 `- ~/ g
例如:
: l/ [! i, X a
在我们上面的例子中,调度器会立即执行9点和10点的任务,并等待11点时,继续按正常的调度执行。
, N9 c0 p5 z& U) `6 l6 x
备注:当处理misfire时,我们同样要注意到,实际job执行的时间,已经滞后于应该执行的时间。这意味着,你不能简单地的依赖当前系统时间,而是应该使用 JobExecutionContext .getScheduledFireTime()去获取。
/ F) _' U) H, P1 k' Y) y3 `' K3 Z
view sourceprint?
1 U# q+ g0 p( }: i/ B: Z
1.def execute(context: JobExecutionContext) {
0 \/ t" j0 y$ ~2 j, Q+ J: K# z
2.val date = context.getScheduledFireTime
5 h: J- s6 M( X' O' v3.//...
1 c( l" |* s+ U) d* j+ ~2 i& E
4.}
/ T' A u$ q: y; f: u1 A: s+ u! p5 Y! N$ ~
6 n/ \! V: l6 i, Q, X( F/ S
withMisfireHandlingInstructionNextWithExistingCount
W3 E7 ?* ^' S1 u% D6 w$ F
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT 调度器不会马上有反应。它会等待下一次执行,然后根据应该调度次数去运行trigger。
6 y7 I! v( w% g2 @' b# ^8 m: f" Z
See also: withMisfireHandlingInstructionNextWithRemainingCount
/ r A1 x. C8 n4 H, E1 w" J例如:
' ]6 A8 [- n, \9 J8 B% O
在10点15发现2次misfire。调度器会等到11点,继续执行,并会每小时执行1次,共执行8次调度操作,直到下午6点停止(本该4点停止的。)
: _3 G6 Z$ p1 C. v0 ?9 N
withMisfireHandlingInstructionNextWithRemainingCount
+ Q, D f7 ^4 i9 o
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 调度器会抛弃被misfire的操作,然后等待下次执行。这样,执行的总次数,就会小于配置的次数。
# E; i" X' O. N8 a' ^) u例如:在10点15,2次misfire的执行都被丢弃了。调度器会等到下个执行时间-11点,然后继续触发其余的trigger,直到4点。事实上,这种情况就像misfire从未发生过一样。
2 L% Y- F7 d4 t2 a+ w- |withMisfireHandlingInstructionNowWithExistingCount
/ o; a1 J% q |MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
! u- z) z: K3 p8 [# \! n
第一次misfire的trigger会立即执行,而后会按设置的间隔,依次执行剩余的trigger。实际上,就像misfire的trigger的第一次触发时间,被平移到了当前时间。
8 u6 h" ~, J' t c5 }( W例如:
7 P( n; p1 b: ^# a5 R7 m! u9 T调度器会在10点15第一次运行misfire的trigger,然后隔1个小时,在11点15执行第二次。共执行8次,最后一次,在下午5点15。
' u4 D1 J7 I. E- T. m+ L( r
) Y6 ?0 W2 k, Y6 J; ~( d
withMisfireHandlingInstructionNowWithRemainingCount
$ X" M' _5 U; c4 C! zMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
P. u0 W! m9 m0 F第一次misfire的操作,被立即执行。其余被misfire的操作,会被抛弃。
& W2 H1 ^( i c0 L2 {+ d Z
剩余没有被misfire的trigger,会按固定间隔被触发。
) P$ S5 q( E/ ^ O5 C例如:
0 Q/ w, D! S0 Q3 f2 C) P
调度器会在10点15运行第一次被misfire的操作(9点的。)。然后,它抛弃其余被misfire的(10点那一次)。最后,它会等1小时继续触发6个trigger:
/ Z+ ^7 p& G( i: ? s7 C. l6 s11:15,12:15.... 4:15 PM。
3 W; U( x' [5 p. t5 _) r+ M% X) L% {$ a# ^2 k
: ]* O) [6 l: T
这是一个基于指定间隔、并重复无数次的trigger:
" d1 |+ A! X- i
view sourceprint?
3 b$ t6 ]! G/ B: D8 n
01.val trigger = newTrigger().
+ O( v$ p% O, ^02.startAt(dateOf(9, 0, 0)).
3 G5 \" A$ n" E/ z; L' f+ {03.withSchedule(
8 I/ `6 p7 o2 \+ ^
04.simpleSchedule().
8 Z% d8 _0 A6 N! l) M
05.withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY).
' \5 P$ g7 Z* z) o6 |
06.withIntervalInHours(1).
/ d2 W# p9 [9 z: M1 B6 ^) p
07.WithMisfireHandlingInstructionFireNow() //or other
; G* L0 I$ Y, W: t7 G0 n* j08.).
! Q7 F- U, d3 q2 u
09.build()
# `+ Y; p! _. M8 E5 e- c0 R: T$ @
, F/ g" q* r8 r6 M. \( L7 D* K( @
trigger应该从今天9点开始(startAt(dateOf(9, 0, 0)),每隔小时触发一次。然而调度器在9点到10点都没有执行job(比如关闭了系统、线程不够等等。。前面有介绍),并且在10点15时才被发现,misfire了2次。这种情况比那种执行执行次数的trigger更加普遍。
( S) g7 n# l7 r& p
指令 Instruction 意义 Meaning
% _# E8 |" t* E3 zsmart policy - default See:withMisfireHandlingInstructionNowWithExistingCount
! X' L8 `" ~0 y# P& Q+ T& hwithMisfireHandlingInstructionFireNow
0 k* a( I7 H, B+ YMISFIRE_INSTRUCTION_FIRE_NOW See: withMisfireHandlingInstructionNowWithRemainingCount
) G% i; Z. h* g' R7 c
withMisfireHandlingInstructionIgnoreMisfires
) i7 W1 O0 a+ f/ k
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
, B4 C0 I0 F3 L8 T+ C' e; Thttps://jira.terracotta.org/jira/browse/QTZ-283# n: n, j# _7 E: e* h/ E0 |
调度器会立即执行所有misfire的trigger,然后继续正常调度。
8 }7 x0 x0 m0 g& Z
例如:
P+ b0 n# E( f7 `* v2 G j! A3 j9点和10点的trigger会立即执行,下次执行将按计划执行(下一次是11点执行)。
/ a4 C- L" P0 M) v& \" Q
; R& e( i) A; f8 v4 k! V3 u, J
withMisfireHandlingInstructionNextWithExistingCount
7 |( h6 [. _, g& N+ T1 U3 K
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT See:withMisfireHandlingInstructionNextWithRemainingCount
1 A# ~6 I: {; n0 K& F3 U8 d$ j" _, gwithMisfireHandlingInstructionNextWithRemainingCount
. c- {8 q$ F0 [. p5 e, O
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
8 E6 |: {% |* s! @1 \. t不做任何事情,misfire的情况被忽略掉。然后,调度器按设置的间隔等待下次执行。
$ b2 d G( @( S! f" ?
例如:
/ u/ g; K) w+ Y ]& Z% @+ X( u
9点和10点misfire的执行被忽略掉。第一次执行会在11点会开始。
q/ o1 w$ s* hExample scenario: Misfired execution at 9 and 10 AM are discarded. The first execution occurs at 11 AM.
* O& @* `# M2 n$ z9 h
, n3 ?5 u' e; X$ W8 A5 s' ewithMisfireHandlingInstructionNowWithExistingCount
. q: B8 O! j4 M# t+ H; Y) R2 D
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
, N- I9 o. J. I7 h4 SSee:withMisfireHandlingInstructionNowWithRemainingCount
9 n1 P; G: @- T3 q3 w! s
withMisfireHandlingInstructionNowWithRemainingCount
2 p' A D3 p* x8 T& ~MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
5 r; k3 d2 }8 l; x( M3 _0 w' m& k
8 u3 f& A, U+ p/ a) M/ R第一次misfire的执行会被立即运行,其余的被忽略。下次执行会在设置的间隔时间后被触发。实际上,就是第一次执行被推迟到了当前时间。
, V4 L' P6 B6 m* p; h
例如:
! C; l) i2 P% T2 c3 s7 \3 [* h调度器在10点15立即执行misfire的trigger,然后等待一个小时后,在11点15时,执行第二次。以后会每隔一小时。
; s2 ^- G3 u) O! f! [6 Z$ h1 b6 r7 F5 }- f! l, Z
' r' c4 z" t* k$ ?6 m定时触发 CRON trigger
- B2 n9 @4 J) Q; t' t/ u
定时触发是Quartz中最常见的。它有另外两个有效的trigger:DailyTimeIntervalTrigger(比如每25分钟一次)和CalendarIntervalTrigger(比如5个月执行一次)。They support triggering policies not possible in both CRON and simple triggers.(不会译- -!),但是他们和CRON trigger一样,支持同样的misfire handling instructions(失火处理指令)。
# ]) h5 E2 b7 Y6 v2 ]
view sourceprint?
2 y+ m; E/ h- U: l4 D, b" J& k: G1.val trigger = newTrigger().
! d/ p( ^8 L% T2 Z8 R1 C2.withSchedule(
% W( t7 Z0 B4 n" J% R2 q: @
3.cronSchedule("0 0 9-17 ? * MON-FRI").
4 \0 L; h& Z1 u" v- m
4.withMisfireHandlingInstructionFireAndProceed() //or other
5 @ [, d/ h0 R$ n2 f1 B5.).
8 P6 d2 i/ H$ @
6.build()
& G: a9 S7 P9 N" _9 k5 y% f0 F; s6 a3 |% F6 T8 U
- l3 d5 x. h T5 p) r: {
这个例子是,trigger在每周一到周五的早上9点到下午5点间,每小时被触发一次。但是两次触发被misfire了,并且在10点15时,才发现这个情况。请注意,他们的失火指令效果与普通trigger是不同的:
$ [4 i$ j3 F) b* e) W4 i4 D指令 Instruction 意义 Meaning
$ t1 l1 T- b. @, `smart policy - default See: withMisfireHandlingInstructionFireAndProceed
6 M5 G" ~6 v1 G. L
withMisfireHandlingInstructionIgnoreMisfires
$ e7 j/ \! u. H; k+ l O- xMISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
2 P& k, a4 ]2 S# D" G
https://jira.terracotta.org/jira/browse/QTZ-2839 F, ]" b' I0 Y4 _9 f
所有被misfire的执行会被立即执行,然后按照正常调度继续执行trigger。
7 U5 o- W$ z; s; g; p% a例如:
0 c: k. Z O( y! G, K; P
9点和10点的执行(misfire的2个)被立即执行,下次执行将在11点被准时执行。
& c0 ]4 x$ V( H; h
withMisfireHandlingInstructionFireAndProceed
8 b" v ]4 ?7 S" N* M1 G
MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
: G0 E6 j6 |1 h立即执行第一次misfire的操作,并且放弃其他misfire的(类似所有misfire的操作被合并执行了)。然后继续按调度执行。无论misfire多少次trigger的执行,都只会立刻执行1次。
- @- N. t* L }* d7 T8 _例如:
9 Y" j6 H! Y+ A" o5 w9点和10点的被合并执行一次(换句话说,10点需要执行的那次,被pass了)。下次执行将在11点被准时执行。
1 L2 q& z- c, M4 m
withMisfireHandlingInstructionDoNothing
- _' I4 g0 y" B/ X+ O) U
MISFIRE_INSTRUCTION_DO_NOTHING
# J0 D) t9 N( y& ?所有被misfire的执行都被忽略掉,调度器会像平时一样等待下次调度。
. G0 R/ g7 e* o F
例如:
" T$ C8 }+ Z7 Y
9点和10点的被忽略掉,好像什么都没发生一样。下次执行将在11点被执行。
+ Z5 f! Z1 k; V1 X% K9 M p8 D
! m5 ^* n5 s' V- Z' l$ o. aQTZ-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,关注下。)
7 j- G# j+ J1 ~; q( r, l7 ~
+ |5 @0 M- g I7 n9 C如你所有,根据实际的设定,不同的trigger会有不同的行为。此外,虽然它提供了smart policy(明智的决策),但是真正使用时,还是要取决于业务需求。
1 C2 r3 w4 g2 N: d$ |* }5 ^, U
从本质上看,主要有三种策略:忽略,立即运行然后继续正常执行,忽略misfire的并等待下次执行。( 原文: ignore, run immediately and continue and discard and wait for next. )
1 ~ h. c* L G0 _
它们有不同的应用场景:
8 p/ K; u1 Y3 N( ~& q6 S2 w5 b当你需要确保每次调度任务都要被执行的时候,即时它意味着多个misfire的trigger会被触发,那么用ignore policies。试想一下,有一个任务,需要每小时,都根据上一小时的订单去生成报表。如果服务被关闭了8个小时,那你可能仍然是尽快得到那些报表的。这种情况下,配置ignore policies,调度器会尽快将那8小时的调度任务运行一遍的。尽管晚了几个小时,但是仍然是被执行了(最终报告到手了。^_^)。
0 a2 W' s7 j0 n+ z
当你需要任务被定期执行,并且当出现misfire的情况后立即运行一次的时候,那么使用now* policies。试想一下,一个任务是每分钟清空文件夹 /tmp。如果调度器在20分钟内繁忙,最后终于可以执行这个任务了,那么你肯定不会希望它执行20次的!一次就足够了,但是要尽快执行。而后,再回到正常的执行间隔--1分钟。
: ^+ Y8 p7 d( c. L3 ?' b" s
当你希望任务能在特定时间点运行的时候,使用next* policies不错。比如你需要在每个整点后15分钟抓取股票的价格。它们的变化非常快,然后现在已经整点后20分了,那么不必烦恼。你刚好错过了5分钟,但是现在你已经不在乎(那时候的价格)了。这时,一个时间间隙总好过一个不准确的值。这种情况Quartz只要跳过misfire的操作,等待下次执行就好了。
" j8 e2 W0 p: r& [( ?+ f, N
7 P3 ]6 [) G9 r! S(此文仅为作者观点,我在翻译过程中,其实也有不太明了之处,但是总体来说,还是清晰的,希望大家在以后使用工具时,也更多的关注工具的一切内在功能。)
' W j! N. D/ a5 w9 z; @: A; y c2 R# N" r( M1 G6 T d8 {
7 q" ?( b+ w3 Y3 S3 ~. e1 t5 F
再次注明,原文地址:
http://java.dzone.com/articles/quartz-scheduler-misfire. _0 p' Y4 c% s4 t) p! c! Z" W
如转,请尊重原作者,贴上链接。
* G0 d# M. O' |, R! z1 V6 L# d7 Q/ o. C
. M+ d9 H3 F0 w* _1 z( ]# |