如果你在用quartz的时候,也看到这个日志信息(Handling 2 trigger(s) that missed their scheduled fire-time.)了,并且发现quartz管理的任务,都不再被触发了,那么,你可以看看这篇文章。
6 M' ~0 W& h$ J! Q' e
- m: I1 g' j$ s( J+ h# w9 P
原文地址:
http://java.dzone.com/articles/quartz-scheduler-misfire
4 t* e4 F3 M! p; ]9 }由于本人英文水平有限,部分地方会直接用原文英语代替,另,部分翻译可能比较晦涩,望理解。
% N: U6 Y, M$ g" s4 C
- t! I4 h8 E( u常见词:
8 h; q6 t8 P9 ^/ N" y, Dmisfire
http://fanyi.baidu.com/#en/zh/misfire 以下统一用misfire,汉语无法贴切表达
8 @/ X# L* ^4 I8 c- w
misfire instruction 失火(没启动起来后的)指示
* q1 I; M; P1 W
smart policy,明智的决策
& e* {& E2 [' q& e7 ^7 |misfired 失火了,没启动起来的意思
& F. x5 X ]8 _" I5 z/ x* t; B
worker thread 工作线程,辅助线程
( @4 ?+ v! u6 m$ Y8 d/ ^; E' K
1 d3 i% O" I/ F, {4 A2 q【翻译】
# `- L" A+ `& n9 o) Q" c有时候,Quartz并不能如你所愿的运行你的job。这里有3个原因:
& ?- J9 K8 ~) ^8 R3 N- n
1.所有的woker thread(工作线程; 辅助线程)都在运行其他的job
. f2 V( E# z7 _& s3 }8 K
2.scheduler(调度器)down了(关于这个down。我不太明确是shutdown了。。还是挂掉了。因此下文依旧用down。)
7 h! x# M# n' a n! o6 F6 v: U3.任务被安排在过去的某一时刻启动(此可能为代码错误)
- @0 I$ g2 Q7 f9 n! K! j2 G" d1 F }* E# J7 Y
你可以简单地通过配置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,汉语无法贴切表达)。
3 U9 O& O# z3 G+ I' J5 W1 a你知道当这种情况发生的时候,Quartz能做些什么吗? 其实,Quartz有许多的策略(叫misfire instructions,失火指示)可以处理问题,并且当你没有去想这方面问题的时候,它也有许多默认策略。但是为了使你的应用更加稳定和可预测(尤其是在高负载和可维护性上),你应该有意识的去确保triggers 和 jobs工作正常。
% [9 d: @/ j2 ^
基于你用的trigger,会有不同的配置选项(对misfire instructions有效)。当然,不同的trigger也会使Quartz有不同的行为(叫做smart policy,明智的决策)。尽管文档中有misfire instructions的描述,但是我发现都很难理解它所想表达的意思,因此,我写下这篇简短的总结。
. Q: u9 [4 h' r1 l! W, U在我深入细节之前,还有一个配置需要说明下:org.quartz.jobStore.misfireThreshold(毫秒级),默认是60000(一分钟)。它定义了trigger被认为是misfired了的时限。
5 y- t& @- S. e, i7 D基于默认配置,如果trigger应该在30秒以前被触发,那么很愉快地,Quartz就把它搞定了。这种延迟(delay)不能叫失火。
9 Z8 c6 }' \; o# o4 S7 B* o
然而当trigger被发现,延迟了61秒时,那么专门的“失火处理者(misfire handler thread)”就会按照misfire instructions去处理它了。
: f- o8 [/ u0 u' o/ @为了测试效果,我们将这个时间设置为1000(即1秒),这样就能很快的测试“失火”了。
; r7 h' Z3 [* _9 {$ X; p6 @& E
" |% f4 c- [' \+ f/ _: w4 `( M8 D7 O$ t, V- w. l4 [1 @# A5 T" G
第一个例子,是一个不需要重复触发的普通trigger,我们来看看普通trigger调度器是怎么处理“失火”,并让它运行一次的:
' g7 Z% F9 b* v0 X! g% ]9 `) ]/ z【原文:Simple trigger without repeating In our first example we will see how misfiring is handled by simple triggers scheduled to run only once:】
( E- J. C' ?. Y8 Vview sourceprint?
' o+ t1 Z9 \ p1 s/ d, g2 N
1.val trigger = newTrigger().
0 C' ~8 M: K# _9 h( t2.startAt(DateUtils.addSeconds(new Date(), -10)).
I4 s1 f# v8 G
3.build()
2 [ y, h; l( ?
K0 S, I, R! i2 W% m, {1 s) E' Z. X- ]# ?/ w
同样的trigger,但是明确设置了misfire instruction handler(失火处理者):
" |9 d0 ?+ X o+ e. E- H Dview sourceprint?
! g Y" ~) l. A0 d1.val trigger = newTrigger().
5 s' k- H$ l5 ^' \3 Y
2.startAt(DateUtils.addSeconds(new Date(), -10)).
* ^1 R/ m3 G3 w# w3.withSchedule(
) X: ]2 U+ {7 I' f5 Z& Z4.simpleSchedule().
$ A& r& n- V( j( ]% X) t' n5.withMisfireHandlingInstructionFireNow() //MISFIRE_INSTRUCTION_FIRE_NOW
8 u! g7 F4 t+ q. y- b- |6.).
. T9 }2 @( r1 {: G; x! c7.build()
# Z t+ C) S. A- `
8 n# A0 e9 ]2 b1 M( W- i5 s0 D4 J r* Q
为了测试,我将trigger设置为10秒前被调度(即当创建后,就已经晚于启动时间10秒)。在实际使用时,我们基本上永远不会这么设置。
7 w3 A9 k" G9 O2 j$ M' }换句话说,如果我们正确的设置了trigger,但是当需要被调度的时候,调度器down了或者没有空闲的worker thread了。那么,Quartz怎么处理这种extraordinary(罕见,古怪)的情况呢?
$ {" M" D8 f0 |- D
在第一段代码中,没有设置misfire instruction(so called smart policy is used in that case 这句不太会翻译。。。。)。
# r6 t6 a8 Y. A3 B
第二段代码中,明确指定了当misfire发生时,我们希望采取的行为。
- h: J. }5 r7 F0 E" y来看下表:
5 |9 T3 a0 F; g- \. B6 Y& O- r, r- `& R2 N7 ^
指令 Instruction 意义 Meaning
: z M" J+ z4 [
smart policy - default See: withMisfireHandlingInstructionFireNow
3 K5 F' d; F0 L2 r' w
withMisfireHandlingInstructionFireNow
9 ^9 r! A& o: K. B% l, J" j* h
MISFIRE_INSTRUCTION_FIRE_NOW 调度器发现misfire情况后,立即执行job。
3 A3 O7 ~; J1 `- _" }这是smart policy。
( h5 I; N6 P9 C- A% g
例如:
6 g/ \4 C0 P5 ]& B4 g3 Y) P% W. b
你让一些系统清理功能在2点执行。但是很不幸,应用在那段时间由于维护,关闭了,直到3点才恢复。这样trigger就misfire了,然后调度器会尝试修复这种情况,在3点启动后,尽快执行。
( T! x7 @3 U- z
withMisfireHandlingInstructionIgnoreMisfires
: |+ Q0 ], ~9 o$ j9 ]+ MMISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY See: withMisfireHandlingInstructionFireNow
1 J% l$ H7 A1 q4 P1 W7 VwithMisfireHandlingInstructionNextWithExistingCount
1 \% i1 p2 U) c1 v) ]1 l9 pMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT See: withMisfireHandlingInstructionNextWithRemainingCount
/ ?$ F* S E, ^2 ^+ t( W
withMisfireHandlingInstructionNextWithRemainingCount
: H* J; z7 |. x" Z" _* E) QMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 什么都不做。misfire被忽略了,并且没有后续的执行。当你想要彻底放弃被misfire的执行时,可以使用这个指令。
' a4 w `* l4 v/ t" B例如:
' ]6 I* l* k+ z) J
trigger是要启动录制一个电视节目。但是被misfire了,2个小时候,才发现。
# g/ u. a r+ j8 ~% g, l) p【PS: 这个不是太理解,只是按照原文翻译过来,如果要用,请自行测试。。。】
$ K% C* w5 J( a% _% u
withMisfireHandlingInstructionNowWithExistingCount
& E% I8 w& Z; q7 ]9 X
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT See: withMisfireHandlingInstructionFireNow
2 x W* D- [5 a |9 E( Y1 R
withMisfireHandlingInstructionNowWithRemainingCount
3 }/ ]" P. i+ ]) N, ~: e
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT See: withMisfireHandlingInstructionFireNow
4 O6 [, Y- t8 U$ K& U/ o7 \ H
' T9 {$ T5 M8 k/ p1 g1 e: `
' t' ~ B3 f( O- k* v& t$ o4 a8 \普通trigger重复执行指定次数。这种情形更加复杂。想象一下,我们有一些需要重复执行指定次数的job:
0 o- N/ A4 k9 }. K
view sourceprint?
& t0 s; g! G1 |7 L2 }
01.val trigger = newTrigger().
) D5 }! x. L) H- B6 F02.startAt(dateOf(9, 0, 0)).
! ]# Y7 [$ c3 K: Y1 c03.withSchedule(
/ X) f) T: h7 z9 z) m1 | @04.simpleSchedule().
- b7 l2 K8 r. w2 f' l3 q/ ?05.withRepeatCount(7).
8 n; U/ I1 j8 h. Z7 |) M
06.withIntervalInHours(1).
0 L+ \" j6 w: r
07.WithMisfireHandlingInstructionFireNow() //or other
& ^* w) X" E/ r$ O8 `0 H- O, V
08.).
3 L4 h5 U V& a1 c% b& Q
09.build()
1 b# O7 Q0 r. h
) } W) t5 K; W0 C
# U, Q, K* V N! C. m& E6 h e在这个例子中,trigger从今天9点开始(startAt(dateOf(9, 0, 0)),共触发8次(第一次执行,和7次重复)。
2 G3 ?+ f! H0 F5 L7 O
按理,最后一次执行应该在下午4点被触发。假设由于某些原因,在9点和10点调度器没有执行job,并且直到10:15才被系统发现misfire,也就是misfire了2次。这种情况下,调度器会怎么样呢?
. G q! U' L, T, c. ?: K
指令 Instruction 意义 Meaning
( q1 D( t; E a
smart policy - default See:withMisfireHandlingInstructionNowWithExistingCount
$ ?& f) M, B5 ?withMisfireHandlingInstructionFireNow
- M3 M! ?) ]$ f* H* T: g% I
MISFIRE_INSTRUCTION_FIRE_NOW See:withMisfireHandlingInstructionNowWithRemainingCount
% }9 F2 h8 n: m1 m0 p3 \
withMisfireHandlingInstructionIgnoreMisfires
- z. b' u, m5 `7 ^' T
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY 尽快启动所有被启动的trigger,并将调度置为正常。
* s' X! c+ o/ E例如:
7 V9 v7 D$ O; ~* z在我们上面的例子中,调度器会立即执行9点和10点的任务,并等待11点时,继续按正常的调度执行。
# ?5 d& Q8 k2 N& X; |6 d! h. r
备注:当处理misfire时,我们同样要注意到,实际job执行的时间,已经滞后于应该执行的时间。这意味着,你不能简单地的依赖当前系统时间,而是应该使用 JobExecutionContext .getScheduledFireTime()去获取。
4 C1 a9 ^1 R8 H6 w
view sourceprint?
4 ]8 O; [1 N! V4 b$ E% o
1.def execute(context: JobExecutionContext) {
9 v9 Q' v& c" C8 ^. U2.val date = context.getScheduledFireTime
% d0 E- v, C7 ~' e
3.//...
$ }! X0 E7 Z5 N. x2 B4.}
. m8 S* {& P6 g/ \* c* C0 }# q; w c+ G4 d
+ ~- w# y8 y% [: j- y) K% YwithMisfireHandlingInstructionNextWithExistingCount
6 S/ c k( C% L. A$ E' S7 a+ I
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT 调度器不会马上有反应。它会等待下一次执行,然后根据应该调度次数去运行trigger。
. K; G6 J, d6 \0 s0 Z, R. T+ eSee also: withMisfireHandlingInstructionNextWithRemainingCount
6 u/ I& P1 z, i, Y9 F. @
例如:
# l u L2 ~6 N2 Q3 l; \
在10点15发现2次misfire。调度器会等到11点,继续执行,并会每小时执行1次,共执行8次调度操作,直到下午6点停止(本该4点停止的。)
' [" R- D# i( j4 \$ Z: H wwithMisfireHandlingInstructionNextWithRemainingCount
0 ~' r& ~" d) C" V; C9 B% gMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 调度器会抛弃被misfire的操作,然后等待下次执行。这样,执行的总次数,就会小于配置的次数。
7 R% K# }3 y& n8 r& Y3 H0 \- y
例如:在10点15,2次misfire的执行都被丢弃了。调度器会等到下个执行时间-11点,然后继续触发其余的trigger,直到4点。事实上,这种情况就像misfire从未发生过一样。
8 E8 Y5 ]& C% ?5 Z8 L' h9 PwithMisfireHandlingInstructionNowWithExistingCount
1 X6 C1 f1 }. \) `MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
/ |6 G4 d7 X6 F0 ]$ q4 u
第一次misfire的trigger会立即执行,而后会按设置的间隔,依次执行剩余的trigger。实际上,就像misfire的trigger的第一次触发时间,被平移到了当前时间。
( B* s; _* W. \. y例如:
N" }# ]: V9 E C1 ~
调度器会在10点15第一次运行misfire的trigger,然后隔1个小时,在11点15执行第二次。共执行8次,最后一次,在下午5点15。
" E* ]0 _7 G3 t5 B& {' N# z
( ~: R. w6 J9 Z, CwithMisfireHandlingInstructionNowWithRemainingCount
9 m4 c" I2 {, G, j( M. Y- [$ |MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
8 Q' l( c! b. b! T5 v1 W, @第一次misfire的操作,被立即执行。其余被misfire的操作,会被抛弃。
7 Y0 w F' y. `4 X- e& Z- V f K剩余没有被misfire的trigger,会按固定间隔被触发。
$ Q/ w' T. w0 h1 o2 w/ C ]8 p
例如:
# V' ]1 ?' S: U7 ]9 S0 o# h" O调度器会在10点15运行第一次被misfire的操作(9点的。)。然后,它抛弃其余被misfire的(10点那一次)。最后,它会等1小时继续触发6个trigger:
. _; w8 r2 r( t; O6 G; D
11:15,12:15.... 4:15 PM。
& b- M/ r6 p% c/ Z2 k
( z0 L* w8 V6 V: u5 z) Z d
% n1 u3 ~0 U; j; g, F' R8 a这是一个基于指定间隔、并重复无数次的trigger:
: O/ H* L; c' k& l0 }view sourceprint?
7 n1 V8 _* j0 `, ]
01.val trigger = newTrigger().
9 [% T+ K) w9 ]/ Q0 k' J+ v7 j02.startAt(dateOf(9, 0, 0)).
% l! E! a1 u( p2 s03.withSchedule(
7 R7 ~, o' k5 e' ?
04.simpleSchedule().
2 t! s2 ?" z3 _7 W5 u
05.withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY).
' E8 i: o, ]# M+ W/ ]9 V! h
06.withIntervalInHours(1).
1 T% W- g* ~" ?+ g3 ~07.WithMisfireHandlingInstructionFireNow() //or other
: }+ j" K6 }: E& X# y$ |, j) l' \08.).
, ~1 p* q& q" [* {" F
09.build()
" \/ z' H* }3 x) y3 z( m% E' Y/ N% S& ]
! R* k2 e* ` a9 f( v0 dtrigger应该从今天9点开始(startAt(dateOf(9, 0, 0)),每隔小时触发一次。然而调度器在9点到10点都没有执行job(比如关闭了系统、线程不够等等。。前面有介绍),并且在10点15时才被发现,misfire了2次。这种情况比那种执行执行次数的trigger更加普遍。
. K$ Q* ?; C9 Q指令 Instruction 意义 Meaning
: e" z8 Q6 u2 U5 ?/ O' \7 z8 tsmart policy - default See:withMisfireHandlingInstructionNowWithExistingCount
& @1 v. w" k# qwithMisfireHandlingInstructionFireNow
3 K1 w7 B# X) {7 e/ G2 N9 n
MISFIRE_INSTRUCTION_FIRE_NOW See: withMisfireHandlingInstructionNowWithRemainingCount
0 O2 f* j! u. T$ x. BwithMisfireHandlingInstructionIgnoreMisfires
0 t$ k6 P* g- ^) `
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
' p1 H9 ]: }3 o) p. ?$ e1 l
https://jira.terracotta.org/jira/browse/QTZ-283; d% _+ z% ^% z5 n
调度器会立即执行所有misfire的trigger,然后继续正常调度。
7 Z8 x1 F- k1 E. Y例如:
$ ^ r% g7 B+ G* i1 K/ r2 y" m+ y9点和10点的trigger会立即执行,下次执行将按计划执行(下一次是11点执行)。
' Q* U/ G3 z" t3 {: w
4 |3 W E E: X, T0 J) S
withMisfireHandlingInstructionNextWithExistingCount
2 A. u4 Q3 o" K$ F1 q9 G0 iMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT See:withMisfireHandlingInstructionNextWithRemainingCount
/ w! _3 B+ I& |. a6 |7 [withMisfireHandlingInstructionNextWithRemainingCount
% u$ ^' _. X6 E8 M9 O$ T7 HMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
3 Z7 |- A2 R! o不做任何事情,misfire的情况被忽略掉。然后,调度器按设置的间隔等待下次执行。
8 ]- {* @2 {9 P6 I
例如:
7 F+ K* Q( ^( H6 y$ }" R* T% w, m
9点和10点misfire的执行被忽略掉。第一次执行会在11点会开始。
5 j, Z3 N9 K% y# @2 k
Example scenario: Misfired execution at 9 and 10 AM are discarded. The first execution occurs at 11 AM.
& S1 U$ Z n3 a v- A- ]
1 ^0 e2 v9 D" E2 hwithMisfireHandlingInstructionNowWithExistingCount
9 w( A; j3 B* _MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
8 d( E1 v0 k% R, q% s- ASee:withMisfireHandlingInstructionNowWithRemainingCount
# q1 `- {' E! m6 F# a! WwithMisfireHandlingInstructionNowWithRemainingCount
* F* w8 G( A+ o6 R0 |' n o- D
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
0 Y1 G- P2 E3 f: v7 `' V
) M: e, h0 e2 [. F$ W% z
/ P6 t1 W& H, {3 U第一次misfire的执行会被立即运行,其余的被忽略。下次执行会在设置的间隔时间后被触发。实际上,就是第一次执行被推迟到了当前时间。
( P' L6 z0 K' b# M& I例如:
" Z6 G; `3 Q3 `3 I, s& n$ B4 Y
调度器在10点15立即执行misfire的trigger,然后等待一个小时后,在11点15时,执行第二次。以后会每隔一小时。
8 ^& [( O, \' I4 j4 s/ B) ~
' N! l: P9 H; E( f
; p) z8 y$ y ` K- U4 \( R定时触发 CRON trigger
% w0 ]& v0 O5 i# N M
定时触发是Quartz中最常见的。它有另外两个有效的trigger:DailyTimeIntervalTrigger(比如每25分钟一次)和CalendarIntervalTrigger(比如5个月执行一次)。They support triggering policies not possible in both CRON and simple triggers.(不会译- -!),但是他们和CRON trigger一样,支持同样的misfire handling instructions(失火处理指令)。
' C J$ n8 V% D2 ^- mview sourceprint?
5 [. W* i/ _/ n( l/ s _; H1.val trigger = newTrigger().
6 \# }- z6 g. y( J! z+ ]
2.withSchedule(
5 Q6 H) h d, J' m/ k: W( ]3.cronSchedule("0 0 9-17 ? * MON-FRI").
! C, l& s- A# S4.withMisfireHandlingInstructionFireAndProceed() //or other
9 l- k; q0 q) ^! d5.).
: T' c* y) v1 E' C6.build()
$ J1 |: [9 A: u' }; n4 m% T9 j# B
5 g) U, r7 S' ^$ J4 A
7 s0 g* C9 o" m; W5 {这个例子是,trigger在每周一到周五的早上9点到下午5点间,每小时被触发一次。但是两次触发被misfire了,并且在10点15时,才发现这个情况。请注意,他们的失火指令效果与普通trigger是不同的:
4 d5 N7 M' H# {4 y" `2 C
指令 Instruction 意义 Meaning
) A- f$ g4 A5 X. {4 A+ zsmart policy - default See: withMisfireHandlingInstructionFireAndProceed
* w8 M/ U# b' d) k5 pwithMisfireHandlingInstructionIgnoreMisfires
% }$ o# E0 ^. }& K5 J- {7 a5 p# OMISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
# M, r2 Q: q- v# Q6 l# Bhttps://jira.terracotta.org/jira/browse/QTZ-283
p4 Q; }1 G. j M j8 @) K c所有被misfire的执行会被立即执行,然后按照正常调度继续执行trigger。
3 r( F7 K( W+ {8 `2 B2 Q
例如:
# C& a; c1 g t, V5 j
9点和10点的执行(misfire的2个)被立即执行,下次执行将在11点被准时执行。
- I! u) O" ^& O: o3 d0 d2 t
withMisfireHandlingInstructionFireAndProceed
# u0 w2 Y3 p0 y" ?. C
MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
. D( m# g0 d3 s/ r- p. y立即执行第一次misfire的操作,并且放弃其他misfire的(类似所有misfire的操作被合并执行了)。然后继续按调度执行。无论misfire多少次trigger的执行,都只会立刻执行1次。
: }' _ i8 ~- ?9 L! a' ?+ O6 z
例如:
: m7 g( S6 _, u- y9点和10点的被合并执行一次(换句话说,10点需要执行的那次,被pass了)。下次执行将在11点被准时执行。
0 P$ U. u. S! o# N1 I# x+ b! swithMisfireHandlingInstructionDoNothing
0 }) u T* R: x8 k5 xMISFIRE_INSTRUCTION_DO_NOTHING
& Q0 k3 z; T2 O3 M8 `
所有被misfire的执行都被忽略掉,调度器会像平时一样等待下次调度。
0 y$ S5 R) e* \4 `- q! A- H
例如:
- N& J4 q6 x4 ^+ u# o
9点和10点的被忽略掉,好像什么都没发生一样。下次执行将在11点被执行。
5 O- C4 U5 K! x8 e% ^* B4 @ 7 X. H8 ?; L, H7 l) i/ f) C8 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,关注下。)
W p5 i0 r. s; M2 N
7 b8 m" ~ ^* |0 J! g如你所有,根据实际的设定,不同的trigger会有不同的行为。此外,虽然它提供了smart policy(明智的决策),但是真正使用时,还是要取决于业务需求。
+ V/ W9 r+ }9 D& L3 v) y从本质上看,主要有三种策略:忽略,立即运行然后继续正常执行,忽略misfire的并等待下次执行。( 原文: ignore, run immediately and continue and discard and wait for next. )
5 D) g/ y7 v, T5 t5 V) d+ \ z$ {
它们有不同的应用场景:
6 p; x. M( ^& ]; H# E$ b5 i( X
当你需要确保每次调度任务都要被执行的时候,即时它意味着多个misfire的trigger会被触发,那么用ignore policies。试想一下,有一个任务,需要每小时,都根据上一小时的订单去生成报表。如果服务被关闭了8个小时,那你可能仍然是尽快得到那些报表的。这种情况下,配置ignore policies,调度器会尽快将那8小时的调度任务运行一遍的。尽管晚了几个小时,但是仍然是被执行了(最终报告到手了。^_^)。
3 n" X0 E1 K* j. N当你需要任务被定期执行,并且当出现misfire的情况后立即运行一次的时候,那么使用now* policies。试想一下,一个任务是每分钟清空文件夹 /tmp。如果调度器在20分钟内繁忙,最后终于可以执行这个任务了,那么你肯定不会希望它执行20次的!一次就足够了,但是要尽快执行。而后,再回到正常的执行间隔--1分钟。
: J- G f; X% ^8 ^$ k% o: d当你希望任务能在特定时间点运行的时候,使用next* policies不错。比如你需要在每个整点后15分钟抓取股票的价格。它们的变化非常快,然后现在已经整点后20分了,那么不必烦恼。你刚好错过了5分钟,但是现在你已经不在乎(那时候的价格)了。这时,一个时间间隙总好过一个不准确的值。这种情况Quartz只要跳过misfire的操作,等待下次执行就好了。
# n9 M9 [5 [* M- c5 G: c$ Y
/ J/ B( s( f: V2 C j7 d- ~6 _(此文仅为作者观点,我在翻译过程中,其实也有不太明了之处,但是总体来说,还是清晰的,希望大家在以后使用工具时,也更多的关注工具的一切内在功能。)
$ P) H" a1 K8 v2 n; {4 L
& p) ^* |* ~& j7 W3 {; l
% C/ A7 h( j9 |# E* `& ?6 y
再次注明,原文地址:
http://java.dzone.com/articles/quartz-scheduler-misfire
5 l8 \. |# y# p' q, E如转,请尊重原作者,贴上链接。
. K. @3 s; P+ `
9 A; H# S' @7 @5 }6 m4 h `( n