如果你在用quartz的时候,也看到这个日志信息(Handling 2 trigger(s) that missed their scheduled fire-time.)了,并且发现quartz管理的任务,都不再被触发了,那么,你可以看看这篇文章。
; X m9 [, c6 G+ r
$ x/ X) c/ P+ `3 p' Y原文地址:
http://java.dzone.com/articles/quartz-scheduler-misfire3 V, X# S1 G2 v i
由于本人英文水平有限,部分地方会直接用原文英语代替,另,部分翻译可能比较晦涩,望理解。
9 s" U5 {' K# g" K" W h" Z, |7 T) v
常见词:
: {3 ^* f% |% ^) ~0 s1 x9 L
misfire
http://fanyi.baidu.com/#en/zh/misfire 以下统一用misfire,汉语无法贴切表达
& g; t& Z6 n* Z" G. Qmisfire instruction 失火(没启动起来后的)指示
2 U3 ~/ O0 J- t$ l8 K' E& x/ Asmart policy,明智的决策
# _! [% r/ \- R) Dmisfired 失火了,没启动起来的意思
; i* T7 j% i4 ~6 Oworker thread 工作线程,辅助线程
6 [! p6 M7 i% F* x' p7 j
3 {4 O8 j3 `9 s c5 h【翻译】
* X2 r5 S! p+ H1 \7 G }有时候,Quartz并不能如你所愿的运行你的job。这里有3个原因:
- d" q5 p* X6 Q/ B1.所有的woker thread(工作线程; 辅助线程)都在运行其他的job
$ f* j4 C7 F7 @7 s/ ]2.scheduler(调度器)down了(关于这个down。我不太明确是shutdown了。。还是挂掉了。因此下文依旧用down。)
, ?+ b A' U9 `$ m5 ~9 |. x& F7 X5 ~
3.任务被安排在过去的某一时刻启动(此可能为代码错误)
5 B& t$ P% S9 u7 N. ]
4 X3 P, t" {5 v* D+ D你可以简单地通过配置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,汉语无法贴切表达)。
' C7 L. ?& T# S$ v; S% X2 j你知道当这种情况发生的时候,Quartz能做些什么吗? 其实,Quartz有许多的策略(叫misfire instructions,失火指示)可以处理问题,并且当你没有去想这方面问题的时候,它也有许多默认策略。但是为了使你的应用更加稳定和可预测(尤其是在高负载和可维护性上),你应该有意识的去确保triggers 和 jobs工作正常。
/ @1 c& T/ f2 X" h) g6 V: f9 k基于你用的trigger,会有不同的配置选项(对misfire instructions有效)。当然,不同的trigger也会使Quartz有不同的行为(叫做smart policy,明智的决策)。尽管文档中有misfire instructions的描述,但是我发现都很难理解它所想表达的意思,因此,我写下这篇简短的总结。
/ W: r) I. n; ^1 ^+ ~: N
在我深入细节之前,还有一个配置需要说明下:org.quartz.jobStore.misfireThreshold(毫秒级),默认是60000(一分钟)。它定义了trigger被认为是misfired了的时限。
U2 |* J) a/ E, C+ q$ u0 Z) o$ }
基于默认配置,如果trigger应该在30秒以前被触发,那么很愉快地,Quartz就把它搞定了。这种延迟(delay)不能叫失火。
- q: p" W& [* a! L然而当trigger被发现,延迟了61秒时,那么专门的“失火处理者(misfire handler thread)”就会按照misfire instructions去处理它了。
8 |3 ~% A0 m) ?& X/ R: j, u# g. Z为了测试效果,我们将这个时间设置为1000(即1秒),这样就能很快的测试“失火”了。
& H* D% x9 V6 d) W% u! ]; [3 i$ n3 V4 p0 y
4 q/ }" ]0 I; h1 G& h9 G7 A0 p* ~! Y( B( b" w
第一个例子,是一个不需要重复触发的普通trigger,我们来看看普通trigger调度器是怎么处理“失火”,并让它运行一次的:
: G) K2 m2 s+ |0 ]0 ^( R【原文:Simple trigger without repeating In our first example we will see how misfiring is handled by simple triggers scheduled to run only once:】
. x* s! d4 Y. {% K# fview sourceprint?
8 u' z/ v9 ^# }# ^0 V
1.val trigger = newTrigger().
* I$ R6 F/ ~: @8 _1 ? M+ ]" I. b2.startAt(DateUtils.addSeconds(new Date(), -10)).
: f( Z8 y3 R6 ~* z \
3.build()
; P, @* d0 G/ k1 h
* O" X# p! Q. p! q/ i6 H: [3 E+ x; ^' f5 a) }2 r+ A0 i
同样的trigger,但是明确设置了misfire instruction handler(失火处理者):
+ s: W; e; w/ m( a
view sourceprint?
2 ?% a0 ~- a( t$ _" p6 `. o
1.val trigger = newTrigger().
# B. g6 ~3 A4 S2.startAt(DateUtils.addSeconds(new Date(), -10)).
- j4 g( C# C* {& D# M9 _8 ]1 X# o
3.withSchedule(
4 {3 Y' U- ^6 y
4.simpleSchedule().
$ O0 x% Y& f# ~7 a5.withMisfireHandlingInstructionFireNow() //MISFIRE_INSTRUCTION_FIRE_NOW
) S" R* ~- F( |; M% g' {6.).
3 ~- E7 W3 `/ e: X" Y
7.build()
( h( G1 L/ \1 ~8 e
; q( [( s4 J4 Y- P- [% ]7 e8 h& {0 t* S$ G# K
为了测试,我将trigger设置为10秒前被调度(即当创建后,就已经晚于启动时间10秒)。在实际使用时,我们基本上永远不会这么设置。
5 D% z. u7 E* R) k) y0 b
换句话说,如果我们正确的设置了trigger,但是当需要被调度的时候,调度器down了或者没有空闲的worker thread了。那么,Quartz怎么处理这种extraordinary(罕见,古怪)的情况呢?
) y, Y( w2 S& i" M% R. I1 |# _$ y
在第一段代码中,没有设置misfire instruction(so called smart policy is used in that case 这句不太会翻译。。。。)。
$ q* L( m2 M; ]第二段代码中,明确指定了当misfire发生时,我们希望采取的行为。
& Q8 k- B' R; a! o来看下表:
6 X2 ~0 g3 {. _/ y' g, y9 }5 o: f
1 m3 V: R8 w3 C' g7 Z) Z指令 Instruction 意义 Meaning
* j- E7 n$ g5 {
smart policy - default See: withMisfireHandlingInstructionFireNow
& e0 E' X, d* i. R+ ~' N1 X: IwithMisfireHandlingInstructionFireNow
" g3 Z' w/ q1 @
MISFIRE_INSTRUCTION_FIRE_NOW 调度器发现misfire情况后,立即执行job。
2 c1 Q. [! t5 e这是smart policy。
. }2 `# b$ X- f例如:
. u' D. C. Q$ m/ ]5 b; c m Z0 D- Y2 p你让一些系统清理功能在2点执行。但是很不幸,应用在那段时间由于维护,关闭了,直到3点才恢复。这样trigger就misfire了,然后调度器会尝试修复这种情况,在3点启动后,尽快执行。
3 K y4 U7 |5 s/ ]$ D+ g, UwithMisfireHandlingInstructionIgnoreMisfires
?9 L0 |% ]6 O8 U. i$ Q! [MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY See: withMisfireHandlingInstructionFireNow
$ m1 F5 @# f. @% k$ h! `8 J; O
withMisfireHandlingInstructionNextWithExistingCount
2 f4 ^6 {7 m3 `& U1 hMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT See: withMisfireHandlingInstructionNextWithRemainingCount
" w- ?2 d( }6 T9 @
withMisfireHandlingInstructionNextWithRemainingCount
' i" d1 _ E9 H0 u1 [& _) U, ?MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 什么都不做。misfire被忽略了,并且没有后续的执行。当你想要彻底放弃被misfire的执行时,可以使用这个指令。
; T8 n+ b, i- n* q' n- c
例如:
2 u3 H& a' z4 U% w; ztrigger是要启动录制一个电视节目。但是被misfire了,2个小时候,才发现。
& S& o# I& U- M/ `( I4 G【PS: 这个不是太理解,只是按照原文翻译过来,如果要用,请自行测试。。。】
5 y2 s6 u2 U0 S7 R
withMisfireHandlingInstructionNowWithExistingCount
* Y8 M+ w% T; |9 l. {. N
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT See: withMisfireHandlingInstructionFireNow
$ L- s7 P& B+ a
withMisfireHandlingInstructionNowWithRemainingCount
7 N$ |, [6 Q$ G: M+ ~( o! SMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT See: withMisfireHandlingInstructionFireNow
& p# P8 {3 Z1 {3 V4 ~2 a0 ]; m+ H# t5 ~2 x, `% e3 @/ F" V
' t S% t! r( H0 H" X# S
普通trigger重复执行指定次数。这种情形更加复杂。想象一下,我们有一些需要重复执行指定次数的job:
0 b5 w: a. \. r: m( v/ s
view sourceprint?
6 A! e) O! F, @01.val trigger = newTrigger().
6 x8 Z* b- y4 ^7 r: p J9 v: U
02.startAt(dateOf(9, 0, 0)).
* H6 a8 P; z8 _5 G- F
03.withSchedule(
# ~8 I4 k3 }3 h) P6 a: m
04.simpleSchedule().
0 W/ ] y& ~7 }/ E/ U$ G9 ^& v r4 A6 c05.withRepeatCount(7).
1 z1 U5 w6 J; W" g3 m06.withIntervalInHours(1).
1 P3 |% s- f: C1 n: I
07.WithMisfireHandlingInstructionFireNow() //or other
3 y8 }9 A6 Y7 A9 L( R% @) @! C
08.).
, i: Z+ K: \8 ~2 K7 M
09.build()
) N4 X1 N2 I3 W# [/ G! X8 K, R; b3 ~: a% J y
( M5 Z' A. ^; q( }2 Q在这个例子中,trigger从今天9点开始(startAt(dateOf(9, 0, 0)),共触发8次(第一次执行,和7次重复)。
1 V# p5 o# I4 h3 `8 ?7 N7 t, ~6 x* Y
按理,最后一次执行应该在下午4点被触发。假设由于某些原因,在9点和10点调度器没有执行job,并且直到10:15才被系统发现misfire,也就是misfire了2次。这种情况下,调度器会怎么样呢?
# J; J# `. t& g, I* {
指令 Instruction 意义 Meaning
5 ~% J$ A: ?; y. Wsmart policy - default See:withMisfireHandlingInstructionNowWithExistingCount
" v- {$ Z( S$ u# X& w# J' z" N; WwithMisfireHandlingInstructionFireNow
- B) i0 O) @9 m/ yMISFIRE_INSTRUCTION_FIRE_NOW See:withMisfireHandlingInstructionNowWithRemainingCount
; P# T5 o7 X. O4 x% W9 x( xwithMisfireHandlingInstructionIgnoreMisfires
, q7 Z5 F6 k9 R, ]% W; q# @; k7 `
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY 尽快启动所有被启动的trigger,并将调度置为正常。
5 `: g. K& s6 g/ h6 p [
例如:
! W$ m* \2 E3 k8 C; m5 q: q* F, }% s在我们上面的例子中,调度器会立即执行9点和10点的任务,并等待11点时,继续按正常的调度执行。
0 T6 {" b$ _& Z* T. q. z. K
备注:当处理misfire时,我们同样要注意到,实际job执行的时间,已经滞后于应该执行的时间。这意味着,你不能简单地的依赖当前系统时间,而是应该使用 JobExecutionContext .getScheduledFireTime()去获取。
5 u8 y. O9 X1 F, }1 _2 Y$ @; B
view sourceprint?
b; f: \/ S% N# U2 Y$ K+ Q1.def execute(context: JobExecutionContext) {
6 o; ]! A4 i5 k8 d/ P. A
2.val date = context.getScheduledFireTime
7 A0 m: u' V! Q% B
3.//...
- \0 U% o2 F0 S Y- W7 |4.}
7 a0 Q \& f! Q6 S$ n0 a0 O5 M$ t( n. |0 s& r9 m
0 W- z3 q- S T0 s& J( l1 L
withMisfireHandlingInstructionNextWithExistingCount
2 u. ?# M8 f8 P+ w$ i5 B
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT 调度器不会马上有反应。它会等待下一次执行,然后根据应该调度次数去运行trigger。
' l7 h8 w. h7 |! B: E
See also: withMisfireHandlingInstructionNextWithRemainingCount
! j: P2 H% j* c. p: t `% L8 j例如:
! N: A% j% M3 E! v7 m在10点15发现2次misfire。调度器会等到11点,继续执行,并会每小时执行1次,共执行8次调度操作,直到下午6点停止(本该4点停止的。)
6 ~' e) H& n5 A8 k hwithMisfireHandlingInstructionNextWithRemainingCount
( f5 m5 l) e% }
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 调度器会抛弃被misfire的操作,然后等待下次执行。这样,执行的总次数,就会小于配置的次数。
$ W# k% p! V+ ?/ w* y5 C1 e0 X- G* R N例如:在10点15,2次misfire的执行都被丢弃了。调度器会等到下个执行时间-11点,然后继续触发其余的trigger,直到4点。事实上,这种情况就像misfire从未发生过一样。
6 `3 C( [% g, v/ pwithMisfireHandlingInstructionNowWithExistingCount
0 \9 B; ^: h+ W7 g* [MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
4 V$ H/ _) j# E5 ~5 _# w
第一次misfire的trigger会立即执行,而后会按设置的间隔,依次执行剩余的trigger。实际上,就像misfire的trigger的第一次触发时间,被平移到了当前时间。
' _0 P# E. s* h; A9 d3 [: [
例如:
; p. y8 z1 Q' X0 k5 K o w% V调度器会在10点15第一次运行misfire的trigger,然后隔1个小时,在11点15执行第二次。共执行8次,最后一次,在下午5点15。
4 I* I# I* _* Y% |9 t5 ]9 L; }8 @9 D* @
withMisfireHandlingInstructionNowWithRemainingCount
g: j5 @; m$ d0 g
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
2 O0 z$ V5 a' X7 {6 `5 a% z; l; A2 i
第一次misfire的操作,被立即执行。其余被misfire的操作,会被抛弃。
" X% i" D6 E! K1 o( D剩余没有被misfire的trigger,会按固定间隔被触发。
, A# p+ |- w Z7 x6 K1 m7 w
例如:
8 d4 M, P. b2 F- O
调度器会在10点15运行第一次被misfire的操作(9点的。)。然后,它抛弃其余被misfire的(10点那一次)。最后,它会等1小时继续触发6个trigger:
3 p. f: S1 Y* Q+ t11:15,12:15.... 4:15 PM。
- [8 J1 s) H, `& s7 G; W' k
3 O$ o, ?1 O1 P' P+ |5 ?1 u/ Q) Z3 y
6 L0 H d9 z, [
这是一个基于指定间隔、并重复无数次的trigger:
# k) m/ h) d& c" [4 t
view sourceprint?
; P5 c0 @/ i% ~) X' G! [01.val trigger = newTrigger().
6 Y& p7 B$ O5 d! _02.startAt(dateOf(9, 0, 0)).
) z m6 P, J$ m: d) a03.withSchedule(
: I6 w8 `" {% \) P* v- I4 X
04.simpleSchedule().
8 z; h2 ?3 |) e4 ^/ e2 S
05.withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY).
4 n: o" Q7 Q9 l' _
06.withIntervalInHours(1).
+ r# y! d% K" e: H! E07.WithMisfireHandlingInstructionFireNow() //or other
. {, r, i* f i6 ?& {0 A08.).
( i, L7 R/ W$ D
09.build()
+ j2 l" i6 D; f! V8 @6 ~
( @9 Z, k8 C- M) U- ]) Y
/ [7 x( E2 |9 W9 c6 Q# }; }' }
trigger应该从今天9点开始(startAt(dateOf(9, 0, 0)),每隔小时触发一次。然而调度器在9点到10点都没有执行job(比如关闭了系统、线程不够等等。。前面有介绍),并且在10点15时才被发现,misfire了2次。这种情况比那种执行执行次数的trigger更加普遍。
8 S* `# I) \) H9 V指令 Instruction 意义 Meaning
( j/ M3 p7 u* H# ~& J% D% B8 ?3 M
smart policy - default See:withMisfireHandlingInstructionNowWithExistingCount
( c/ e9 C) U" Y& DwithMisfireHandlingInstructionFireNow
! D) `# ?5 C5 A6 U) j
MISFIRE_INSTRUCTION_FIRE_NOW See: withMisfireHandlingInstructionNowWithRemainingCount
# {* n4 M6 J* W6 ]
withMisfireHandlingInstructionIgnoreMisfires
9 u j+ p0 k; `1 ^( F( o% f1 {' {; J
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
" Q- D9 A) v* bhttps://jira.terracotta.org/jira/browse/QTZ-283
b, A8 h( L2 g; f" o4 n调度器会立即执行所有misfire的trigger,然后继续正常调度。
6 @* K+ A3 L7 c5 H5 M, l* w
例如:
5 s8 l; e$ G7 p, w+ P
9点和10点的trigger会立即执行,下次执行将按计划执行(下一次是11点执行)。
- e/ x3 K' o9 @
; g- R) K! C' mwithMisfireHandlingInstructionNextWithExistingCount
1 P) j* w( u/ q+ ?- c; {2 y( O
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT See:withMisfireHandlingInstructionNextWithRemainingCount
6 s) B8 E6 ^! n9 K. }0 |- U! Z( S
withMisfireHandlingInstructionNextWithRemainingCount
1 o6 f: a+ R+ ~% VMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
, Y1 Y3 k! C4 _8 n n不做任何事情,misfire的情况被忽略掉。然后,调度器按设置的间隔等待下次执行。
) X1 J8 v1 ?1 _* B例如:
* W7 n% s$ g; E1 X9点和10点misfire的执行被忽略掉。第一次执行会在11点会开始。
7 I: r' l" A$ D
Example scenario: Misfired execution at 9 and 10 AM are discarded. The first execution occurs at 11 AM.
% F! b' d% i! r
/ m; H7 v' T9 A
withMisfireHandlingInstructionNowWithExistingCount
, D5 ?* H q6 A! |8 W) c, O: P- k
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
' }. C. ?. k8 ?8 B- {6 PSee:withMisfireHandlingInstructionNowWithRemainingCount
3 t& M& M S, \7 A7 S" T/ Y1 c
withMisfireHandlingInstructionNowWithRemainingCount
1 d" y, @$ H: h. |% A5 Z2 {9 V
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
4 S$ I' o# U. E% {8 t/ T
: F3 l( C' M+ v0 r/ q
0 e) Q$ M7 t) O/ C7 O0 \# I第一次misfire的执行会被立即运行,其余的被忽略。下次执行会在设置的间隔时间后被触发。实际上,就是第一次执行被推迟到了当前时间。
% h, {2 m9 k$ G5 Y# X ?* l/ J# c8 G
例如:
( y+ z: r: `, d f7 m6 N& M调度器在10点15立即执行misfire的trigger,然后等待一个小时后,在11点15时,执行第二次。以后会每隔一小时。
& @( ^) E2 H9 J9 _ }* m' V( m) ]5 q& S: X6 T
$ w* S. q4 U8 K1 @; l定时触发 CRON trigger
- ]: W; @* b& {0 |- L定时触发是Quartz中最常见的。它有另外两个有效的trigger:DailyTimeIntervalTrigger(比如每25分钟一次)和CalendarIntervalTrigger(比如5个月执行一次)。They support triggering policies not possible in both CRON and simple triggers.(不会译- -!),但是他们和CRON trigger一样,支持同样的misfire handling instructions(失火处理指令)。
3 I; M4 w4 H8 S, S0 }5 qview sourceprint?
2 L) \, O3 S6 S" z- N% b' { Z% h+ `& T2 g1.val trigger = newTrigger().
f6 l T! @- d$ t# k9 }3 `
2.withSchedule(
) H( a, h7 q, `$ _3.cronSchedule("0 0 9-17 ? * MON-FRI").
* e8 s3 I3 o0 b% F. U4.withMisfireHandlingInstructionFireAndProceed() //or other
" H& `! }" U. O1 t6 Z' f" N
5.).
- n. k) k2 w% d6.build()
: _0 C1 K% S P4 n+ |* ^+ E3 z9 `4 W. v
0 U, g4 x+ \4 C6 }
这个例子是,trigger在每周一到周五的早上9点到下午5点间,每小时被触发一次。但是两次触发被misfire了,并且在10点15时,才发现这个情况。请注意,他们的失火指令效果与普通trigger是不同的:
4 H0 w" ]- {: o: a3 y1 p
指令 Instruction 意义 Meaning
4 H: F- V) W. F i Y, q
smart policy - default See: withMisfireHandlingInstructionFireAndProceed
) D3 A) q0 U- k9 A% i( w1 m/ p3 _
withMisfireHandlingInstructionIgnoreMisfires
2 [* B. I7 H+ J% x, C) y
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
8 P2 C( B! Z" M1 g6 `+ @
https://jira.terracotta.org/jira/browse/QTZ-283
. e6 l! @; V. j; C. I所有被misfire的执行会被立即执行,然后按照正常调度继续执行trigger。
3 ]) g# i' \/ u: I% l6 D' B. T; X: q
例如:
# p" s' n4 B/ ?4 P9点和10点的执行(misfire的2个)被立即执行,下次执行将在11点被准时执行。
3 u* R( m0 J3 T. V! t5 ]
withMisfireHandlingInstructionFireAndProceed
! s/ }8 e# V2 h: d& z
MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
, e m% Y8 N9 K9 e. ]. d
立即执行第一次misfire的操作,并且放弃其他misfire的(类似所有misfire的操作被合并执行了)。然后继续按调度执行。无论misfire多少次trigger的执行,都只会立刻执行1次。
: ~- l% F- O g2 @0 M X' _
例如:
* ]' B2 _ w- M
9点和10点的被合并执行一次(换句话说,10点需要执行的那次,被pass了)。下次执行将在11点被准时执行。
6 i# L; I& `8 q7 Y2 S' r1 L& a" @withMisfireHandlingInstructionDoNothing
1 y+ p3 c, s4 f2 p7 Y7 p
MISFIRE_INSTRUCTION_DO_NOTHING
; N7 X% P. J- j4 x! O3 l6 u所有被misfire的执行都被忽略掉,调度器会像平时一样等待下次调度。
( c9 u1 A3 K# ]5 q例如:
r5 i) ^4 s+ @8 V
9点和10点的被忽略掉,好像什么都没发生一样。下次执行将在11点被执行。
, y, r2 _( @- F. O. P. p( L+ ^
, Y5 w5 P$ v" d; e. G2 \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,关注下。)
" u3 _3 W6 J. n5 o) }3 Y
1 L' S# n* A' b3 c
如你所有,根据实际的设定,不同的trigger会有不同的行为。此外,虽然它提供了smart policy(明智的决策),但是真正使用时,还是要取决于业务需求。
# T. Y% O" ]- J+ X从本质上看,主要有三种策略:忽略,立即运行然后继续正常执行,忽略misfire的并等待下次执行。( 原文: ignore, run immediately and continue and discard and wait for next. )
' f. [6 i( f* G, J6 S6 f1 \* K它们有不同的应用场景:
5 M9 K0 F5 z/ H) ^
当你需要确保每次调度任务都要被执行的时候,即时它意味着多个misfire的trigger会被触发,那么用ignore policies。试想一下,有一个任务,需要每小时,都根据上一小时的订单去生成报表。如果服务被关闭了8个小时,那你可能仍然是尽快得到那些报表的。这种情况下,配置ignore policies,调度器会尽快将那8小时的调度任务运行一遍的。尽管晚了几个小时,但是仍然是被执行了(最终报告到手了。^_^)。
9 J: P6 F" ]6 I7 d% g
当你需要任务被定期执行,并且当出现misfire的情况后立即运行一次的时候,那么使用now* policies。试想一下,一个任务是每分钟清空文件夹 /tmp。如果调度器在20分钟内繁忙,最后终于可以执行这个任务了,那么你肯定不会希望它执行20次的!一次就足够了,但是要尽快执行。而后,再回到正常的执行间隔--1分钟。
' u, d K# r) {1 @8 o+ m
当你希望任务能在特定时间点运行的时候,使用next* policies不错。比如你需要在每个整点后15分钟抓取股票的价格。它们的变化非常快,然后现在已经整点后20分了,那么不必烦恼。你刚好错过了5分钟,但是现在你已经不在乎(那时候的价格)了。这时,一个时间间隙总好过一个不准确的值。这种情况Quartz只要跳过misfire的操作,等待下次执行就好了。
3 [8 H) Z/ R7 k1 y/ E. P! ~3 \" _
" t4 b [3 m) a(此文仅为作者观点,我在翻译过程中,其实也有不太明了之处,但是总体来说,还是清晰的,希望大家在以后使用工具时,也更多的关注工具的一切内在功能。)
! K( M1 q1 T9 `- o9 G* k2 c
# e7 E- ]6 U0 h- a# U8 J8 w3 `) r) M% c
再次注明,原文地址:
http://java.dzone.com/articles/quartz-scheduler-misfire
; A4 s Q0 T* t6 g- x9 j) m, J如转,请尊重原作者,贴上链接。
7 F9 }$ ]! J3 j) ^
) h+ A9 s( {. P& N8 X" u( a; R. E