如果你在用quartz的时候,也看到这个日志信息(Handling 2 trigger(s) that missed their scheduled fire-time.)了,并且发现quartz管理的任务,都不再被触发了,那么,你可以看看这篇文章。
0 e2 c! C" @2 A' R7 z* Q2 t0 b' Q) N4 `
原文地址:
http://java.dzone.com/articles/quartz-scheduler-misfire0 F. H# Y( ^# D0 t, H
由于本人英文水平有限,部分地方会直接用原文英语代替,另,部分翻译可能比较晦涩,望理解。
+ t$ d4 K1 D& u5 N: `! {0 P
& l2 g& |) N6 I: p: N9 x' |: i
常见词:
# `% Y0 n: F; s9 n& Imisfire
http://fanyi.baidu.com/#en/zh/misfire 以下统一用misfire,汉语无法贴切表达
" [0 T; N$ x' a2 d2 r- s
misfire instruction 失火(没启动起来后的)指示
% b1 F- B& P6 m- q/ f, |
smart policy,明智的决策
% \* p9 z P, I+ z
misfired 失火了,没启动起来的意思
! o) B" c* r3 U: Pworker thread 工作线程,辅助线程
/ ^, C2 g& ^5 ~6 `" ?; X
5 G: Y2 \* b+ Y2 O! P% x【翻译】
: y# Q! W2 e, M- ^9 p: }& ~. N. c5 t有时候,Quartz并不能如你所愿的运行你的job。这里有3个原因:
% \0 V& W$ i( i# U+ b1.所有的woker thread(工作线程; 辅助线程)都在运行其他的job
# T7 k; D. G* U! p, w) P( p2.scheduler(调度器)down了(关于这个down。我不太明确是shutdown了。。还是挂掉了。因此下文依旧用down。)
( n/ A7 m0 _! {4 |" V4 x
3.任务被安排在过去的某一时刻启动(此可能为代码错误)
[1 G& X; H& e7 s+ u
8 D! r% c. \$ E8 r$ O* j8 @
你可以简单地通过配置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,汉语无法贴切表达)。
, g& C" h" C' { w2 L: J
你知道当这种情况发生的时候,Quartz能做些什么吗? 其实,Quartz有许多的策略(叫misfire instructions,失火指示)可以处理问题,并且当你没有去想这方面问题的时候,它也有许多默认策略。但是为了使你的应用更加稳定和可预测(尤其是在高负载和可维护性上),你应该有意识的去确保triggers 和 jobs工作正常。
+ t6 u# X: j* H8 ~$ \+ m
基于你用的trigger,会有不同的配置选项(对misfire instructions有效)。当然,不同的trigger也会使Quartz有不同的行为(叫做smart policy,明智的决策)。尽管文档中有misfire instructions的描述,但是我发现都很难理解它所想表达的意思,因此,我写下这篇简短的总结。
2 A# J% |3 { d# G; z0 [) {
在我深入细节之前,还有一个配置需要说明下:org.quartz.jobStore.misfireThreshold(毫秒级),默认是60000(一分钟)。它定义了trigger被认为是misfired了的时限。
- E5 R1 W, i0 B% S
基于默认配置,如果trigger应该在30秒以前被触发,那么很愉快地,Quartz就把它搞定了。这种延迟(delay)不能叫失火。
$ K4 z6 U8 X9 R- I4 F8 g9 A
然而当trigger被发现,延迟了61秒时,那么专门的“失火处理者(misfire handler thread)”就会按照misfire instructions去处理它了。
) w" k* d, V- v, @; p5 k/ F6 I
为了测试效果,我们将这个时间设置为1000(即1秒),这样就能很快的测试“失火”了。
- {2 d! G$ Z* \3 n
# {' y3 z9 O7 d: d* T* I! r, G' P7 U
5 m5 U; X7 h* A9 q5 M* ?第一个例子,是一个不需要重复触发的普通trigger,我们来看看普通trigger调度器是怎么处理“失火”,并让它运行一次的:
/ d& y" K/ o+ r1 x. J【原文:Simple trigger without repeating In our first example we will see how misfiring is handled by simple triggers scheduled to run only once:】
3 X; k1 y9 A1 o& y
view sourceprint?
# t4 }* v5 O5 {. E+ {9 V1.val trigger = newTrigger().
- z6 s; J% n$ g% ?% j. R2 k2.startAt(DateUtils.addSeconds(new Date(), -10)).
5 M1 Y" R, I8 }6 P- c4 m v
3.build()
+ }: @* O& A5 u( P" ^
9 y/ [3 d: M; L6 }4 s- p$ }# F& _# ~$ |+ T+ @) C! T
同样的trigger,但是明确设置了misfire instruction handler(失火处理者):
$ F' {3 K* z! \! \9 P; x7 A
view sourceprint?
* O" Q/ r" [ P2 G! S9 l& O1.val trigger = newTrigger().
' r) u2 C' _5 p
2.startAt(DateUtils.addSeconds(new Date(), -10)).
$ D0 b* S# v2 y1 k3.withSchedule(
; ]2 K$ {4 w* q# a- \3 E% }
4.simpleSchedule().
- v6 w) G5 R) W. a8 g5.withMisfireHandlingInstructionFireNow() //MISFIRE_INSTRUCTION_FIRE_NOW
7 w1 i3 i' T+ p% s6 W; O m$ c D( J
6.).
) }9 j+ G0 X8 C) Q7 {7.build()
5 g, s$ ?" m3 C# h" Q
. D* d( N6 u- G6 E8 p
0 _) O5 A% q( @5 h x
为了测试,我将trigger设置为10秒前被调度(即当创建后,就已经晚于启动时间10秒)。在实际使用时,我们基本上永远不会这么设置。
" I, |2 v- G' h3 @8 q( D换句话说,如果我们正确的设置了trigger,但是当需要被调度的时候,调度器down了或者没有空闲的worker thread了。那么,Quartz怎么处理这种extraordinary(罕见,古怪)的情况呢?
# u: D3 }* c6 u; j在第一段代码中,没有设置misfire instruction(so called smart policy is used in that case 这句不太会翻译。。。。)。
2 F) }. J* T4 h# H0 l! m& B1 w第二段代码中,明确指定了当misfire发生时,我们希望采取的行为。
* ^0 I# ]- Z% ~! R
来看下表:
" d; b$ ~, ~) ?9 {1 y6 g
G2 v, @1 f& l, Z* q# g* d1 }" ?指令 Instruction 意义 Meaning
* I2 g2 L8 P3 Z% h1 Msmart policy - default See: withMisfireHandlingInstructionFireNow
8 c. [$ l% K' s2 T2 V' J
withMisfireHandlingInstructionFireNow
8 t7 L5 y/ H% g. I4 U
MISFIRE_INSTRUCTION_FIRE_NOW 调度器发现misfire情况后,立即执行job。
' ]: H: I0 l9 o' D9 u6 U" y+ y
这是smart policy。
2 A- }% O; J0 m
例如:
; e0 ^/ v( g; j# k+ t
你让一些系统清理功能在2点执行。但是很不幸,应用在那段时间由于维护,关闭了,直到3点才恢复。这样trigger就misfire了,然后调度器会尝试修复这种情况,在3点启动后,尽快执行。
: f7 m! n+ z, c- `4 n; L' p
withMisfireHandlingInstructionIgnoreMisfires
" @! Q( j* q. O, F4 T2 F8 i- mMISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY See: withMisfireHandlingInstructionFireNow
: B) k. ?1 ` C8 d4 v; @5 wwithMisfireHandlingInstructionNextWithExistingCount
5 z3 R6 @) Y: `8 ^MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT See: withMisfireHandlingInstructionNextWithRemainingCount
1 x' ~$ s X" [6 ~% V
withMisfireHandlingInstructionNextWithRemainingCount
5 e7 U/ a5 a' S3 e& iMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 什么都不做。misfire被忽略了,并且没有后续的执行。当你想要彻底放弃被misfire的执行时,可以使用这个指令。
0 n8 @- A3 v5 h7 ]
例如:
- @. c- {) {: f9 _# h
trigger是要启动录制一个电视节目。但是被misfire了,2个小时候,才发现。
5 V( e7 u/ k( X! r9 @' l0 F
【PS: 这个不是太理解,只是按照原文翻译过来,如果要用,请自行测试。。。】
# u% M. L y8 g6 [# A: jwithMisfireHandlingInstructionNowWithExistingCount
5 R6 A" r: U; Q) G M
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT See: withMisfireHandlingInstructionFireNow
4 A+ |# T k: v. ~$ `withMisfireHandlingInstructionNowWithRemainingCount
. [# Z$ J0 v' V+ t
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT See: withMisfireHandlingInstructionFireNow
! w& j) a p5 ^& C
$ U* \9 O# B% V: z+ z$ q* ^/ K! z, f5 ?2 }4 z Y/ I2 E6 n
普通trigger重复执行指定次数。这种情形更加复杂。想象一下,我们有一些需要重复执行指定次数的job:
! c. `( v z$ sview sourceprint?
) y8 c6 W: u4 l1 w" w' j- l
01.val trigger = newTrigger().
" _2 a$ Q3 p) I" P4 m- ?02.startAt(dateOf(9, 0, 0)).
: o m w) K+ L8 e% q' F9 s03.withSchedule(
/ g3 A' S8 K; o4 v- v) g
04.simpleSchedule().
3 t: W$ n. \- c6 N1 E. k& p
05.withRepeatCount(7).
) L# u b2 i; t- Z( V06.withIntervalInHours(1).
7 [# t( z# |8 i, ~( Q# L5 m, J
07.WithMisfireHandlingInstructionFireNow() //or other
9 q" N9 _* j+ i* V$ m
08.).
( W' M& n3 o5 j' p9 O/ @" W
09.build()
6 [& P+ J ]) T( S. R$ K" P$ o# b2 F% X$ L: {& p/ |; g! \
: j) a" y- Z9 Y3 _9 F在这个例子中,trigger从今天9点开始(startAt(dateOf(9, 0, 0)),共触发8次(第一次执行,和7次重复)。
9 m3 a" Y4 |5 V( b1 M2 i按理,最后一次执行应该在下午4点被触发。假设由于某些原因,在9点和10点调度器没有执行job,并且直到10:15才被系统发现misfire,也就是misfire了2次。这种情况下,调度器会怎么样呢?
' I* w% H, H) a! t$ A9 l指令 Instruction 意义 Meaning
: U. |* w, ?) Z" asmart policy - default See:withMisfireHandlingInstructionNowWithExistingCount
4 f D8 G7 Q" x* y+ rwithMisfireHandlingInstructionFireNow
2 I+ v/ ~" ]9 P, I) x# Z
MISFIRE_INSTRUCTION_FIRE_NOW See:withMisfireHandlingInstructionNowWithRemainingCount
; E# C% M5 b$ p" FwithMisfireHandlingInstructionIgnoreMisfires
4 N' D% }" s; y1 K" F" @: L6 mMISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY 尽快启动所有被启动的trigger,并将调度置为正常。
( @% R4 ?$ s4 B4 ?# \8 n- s# P" d
例如:
+ N! A2 {' K% r# K G' t在我们上面的例子中,调度器会立即执行9点和10点的任务,并等待11点时,继续按正常的调度执行。
: j( y" Y) G' P4 a5 P, Z, }备注:当处理misfire时,我们同样要注意到,实际job执行的时间,已经滞后于应该执行的时间。这意味着,你不能简单地的依赖当前系统时间,而是应该使用 JobExecutionContext .getScheduledFireTime()去获取。
7 x5 \, B# ^1 Y4 |3 ]- n w! w
view sourceprint?
- y* Z; L! P, {- b. L4 j7 X
1.def execute(context: JobExecutionContext) {
; b2 o7 Y" ?" p7 [2.val date = context.getScheduledFireTime
& d- g! f/ Z9 g7 @4 o: w7 N
3.//...
2 r$ X8 i9 f) J
4.}
; {. X: s: \; o H6 n- C" l& ~. b& b4 N7 [: }, Q
0 C& z E" K; e: n7 nwithMisfireHandlingInstructionNextWithExistingCount
* p- s# g" C8 e9 WMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT 调度器不会马上有反应。它会等待下一次执行,然后根据应该调度次数去运行trigger。
) b/ H% p3 j! U/ q! G; p! f! ~/ o I
See also: withMisfireHandlingInstructionNextWithRemainingCount
5 ~' p1 t1 |" J; h( O# d) N
例如:
; E. N" X) w( w! j在10点15发现2次misfire。调度器会等到11点,继续执行,并会每小时执行1次,共执行8次调度操作,直到下午6点停止(本该4点停止的。)
! R% G% _, ~2 _/ z' [
withMisfireHandlingInstructionNextWithRemainingCount
0 ` s# B! Y6 ~4 r; ]
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 调度器会抛弃被misfire的操作,然后等待下次执行。这样,执行的总次数,就会小于配置的次数。
4 `0 S# C' j( o& Y$ _
例如:在10点15,2次misfire的执行都被丢弃了。调度器会等到下个执行时间-11点,然后继续触发其余的trigger,直到4点。事实上,这种情况就像misfire从未发生过一样。
% h1 w) j, {" Q5 y
withMisfireHandlingInstructionNowWithExistingCount
" V1 N/ O9 S- B* z" w& ~MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
3 t1 b, }+ w2 e% F& l# z第一次misfire的trigger会立即执行,而后会按设置的间隔,依次执行剩余的trigger。实际上,就像misfire的trigger的第一次触发时间,被平移到了当前时间。
6 N2 w4 w) r1 i$ I' W2 [5 ^
例如:
' }" n- S G$ O* s
调度器会在10点15第一次运行misfire的trigger,然后隔1个小时,在11点15执行第二次。共执行8次,最后一次,在下午5点15。
2 U8 F: f$ W) p4 M' _' p
5 X/ R1 P4 d+ D/ X; [) I% N- \! |withMisfireHandlingInstructionNowWithRemainingCount
6 x! y0 G: }- e7 u \( V: d7 v; X1 w
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
* H. j4 X' H, ~) i" E' |% I
第一次misfire的操作,被立即执行。其余被misfire的操作,会被抛弃。
! T# w/ w' Y; _剩余没有被misfire的trigger,会按固定间隔被触发。
' q/ t* p9 d& U0 s7 I
例如:
- f& i; Q2 B- A; ^/ Q调度器会在10点15运行第一次被misfire的操作(9点的。)。然后,它抛弃其余被misfire的(10点那一次)。最后,它会等1小时继续触发6个trigger:
$ M6 z! O9 q2 ?2 x) q2 e% A
11:15,12:15.... 4:15 PM。
% N) _* G8 T( [6 y0 e9 J1 D1 ?5 u) F
9 m* R# N6 P' P' n% R$ q5 S
这是一个基于指定间隔、并重复无数次的trigger:
8 k6 h3 a+ A `2 `* mview sourceprint?
) j* O2 r3 i: \/ h7 b& D. D
01.val trigger = newTrigger().
+ U+ G8 `( X" |; I3 h# q, y02.startAt(dateOf(9, 0, 0)).
: q& ]! t$ e8 I0 t! B9 p03.withSchedule(
1 B# Z! {) k8 O5 G
04.simpleSchedule().
) N& K! m1 J" R$ |! ~+ e1 t05.withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY).
% y/ ?, k9 g8 P! @
06.withIntervalInHours(1).
9 h/ q; J& B( e5 k07.WithMisfireHandlingInstructionFireNow() //or other
% b: `" \7 _5 ]) ~9 P5 Q3 e: g8 J08.).
+ o/ f, V& u4 {/ P9 y
09.build()
. k: p) b: F0 d
" Z6 e6 v& m5 e+ [7 j4 J5 K
( m: c+ e2 Z% i3 J6 [& t8 t( o8 `/ j
trigger应该从今天9点开始(startAt(dateOf(9, 0, 0)),每隔小时触发一次。然而调度器在9点到10点都没有执行job(比如关闭了系统、线程不够等等。。前面有介绍),并且在10点15时才被发现,misfire了2次。这种情况比那种执行执行次数的trigger更加普遍。
. U- ~+ B& W/ b( z指令 Instruction 意义 Meaning
3 d8 A: F" v" I. I+ z& ?5 w, y5 Xsmart policy - default See:withMisfireHandlingInstructionNowWithExistingCount
$ q' u" _, P: P# E W+ }
withMisfireHandlingInstructionFireNow
) o4 q& F% }; AMISFIRE_INSTRUCTION_FIRE_NOW See: withMisfireHandlingInstructionNowWithRemainingCount
1 S7 s% F: Q4 E- ZwithMisfireHandlingInstructionIgnoreMisfires
; g% L$ Y1 I5 MMISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
$ k5 p0 F+ @) T3 Shttps://jira.terracotta.org/jira/browse/QTZ-283- g% Y |0 e$ o; H# _( V& ^" {
调度器会立即执行所有misfire的trigger,然后继续正常调度。
7 P6 f2 F5 H# C9 w例如:
. {; z2 B1 [3 b. `" [: z' W' r. l
9点和10点的trigger会立即执行,下次执行将按计划执行(下一次是11点执行)。
( G2 T' [) a( r, A; z& j. l/ a# e5 i5 T
withMisfireHandlingInstructionNextWithExistingCount
- P0 J: y/ n& R' P
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT See:withMisfireHandlingInstructionNextWithRemainingCount
j3 Y' V1 J6 f5 i$ D0 N' A* k
withMisfireHandlingInstructionNextWithRemainingCount
3 y( K j5 p& G+ C9 BMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
. Y% U) |/ N( n) j; P
不做任何事情,misfire的情况被忽略掉。然后,调度器按设置的间隔等待下次执行。
5 s5 B- B: \6 D% O
例如:
! d0 s8 d. n% {* B9点和10点misfire的执行被忽略掉。第一次执行会在11点会开始。
) U7 q# q$ d3 f' b. IExample scenario: Misfired execution at 9 and 10 AM are discarded. The first execution occurs at 11 AM.
- h0 I8 Y# W! m7 M7 Y0 t
7 X. B z- z& v- M4 rwithMisfireHandlingInstructionNowWithExistingCount
* X9 c$ x/ c2 c" s) J1 z2 IMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
! X' Q! p3 C$ K
See:withMisfireHandlingInstructionNowWithRemainingCount
% w7 w1 P, S8 ~0 S
withMisfireHandlingInstructionNowWithRemainingCount
7 H0 G7 a' h7 R! ?( x7 _
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
- \. t6 n/ @% Y U# Z
$ b/ @2 }/ r, R) a$ O6 e% P- G7 s
: y5 G e6 c& d' l/ p4 D% @
第一次misfire的执行会被立即运行,其余的被忽略。下次执行会在设置的间隔时间后被触发。实际上,就是第一次执行被推迟到了当前时间。
) _7 ^, K" j' l* |0 _( L+ s- q
例如:
! V3 U5 O& M$ V5 C' q% s* {# m ?% Y
调度器在10点15立即执行misfire的trigger,然后等待一个小时后,在11点15时,执行第二次。以后会每隔一小时。
. |/ j/ D- }# w1 M% R% X+ M6 w7 F6 S* d7 a# A; p
' ~# b6 Y( z2 A; O3 t$ ?定时触发 CRON trigger
. C8 O$ H; ?/ c2 O定时触发是Quartz中最常见的。它有另外两个有效的trigger:DailyTimeIntervalTrigger(比如每25分钟一次)和CalendarIntervalTrigger(比如5个月执行一次)。They support triggering policies not possible in both CRON and simple triggers.(不会译- -!),但是他们和CRON trigger一样,支持同样的misfire handling instructions(失火处理指令)。
. Y- ~( O( ^6 O: W
view sourceprint?
4 i' U. J9 S* U2 |( j* v; r1.val trigger = newTrigger().
1 Y. `, }9 Y5 j" ]; Q, x2.withSchedule(
; V; L- G. @' k( e4 O3 t% T H/ ^3.cronSchedule("0 0 9-17 ? * MON-FRI").
" j4 C2 O: v4 c" T. M' K- f; u
4.withMisfireHandlingInstructionFireAndProceed() //or other
; i1 j! z, q' L. n h5.).
# g2 G8 k S" w5 D$ C0 a* }* \5 N
6.build()
; N" g& j- R4 T; X
, n2 K- {. g, T; _# G% t; M
# J& {* y+ j S' v# J% r& G, x, c
这个例子是,trigger在每周一到周五的早上9点到下午5点间,每小时被触发一次。但是两次触发被misfire了,并且在10点15时,才发现这个情况。请注意,他们的失火指令效果与普通trigger是不同的:
* h( a4 y% U& s* ]; `$ Z指令 Instruction 意义 Meaning
1 `8 a- W" E/ Q3 k9 e
smart policy - default See: withMisfireHandlingInstructionFireAndProceed
9 _) a+ S4 U- A! V% ]. r' m# c& DwithMisfireHandlingInstructionIgnoreMisfires
+ |. o' u- b% x/ K. @' `4 F
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
4 y5 j8 j+ |6 }9 D4 Bhttps://jira.terracotta.org/jira/browse/QTZ-283/ _* ?, H# Y7 p' h7 W
所有被misfire的执行会被立即执行,然后按照正常调度继续执行trigger。
* {# c: A s' i! Q x7 d例如:
6 x3 R7 X: n! J# D% X5 ]0 B9点和10点的执行(misfire的2个)被立即执行,下次执行将在11点被准时执行。
3 L3 ], t7 ]( Q9 mwithMisfireHandlingInstructionFireAndProceed
( N' a$ H+ y5 u, R+ r A; d) aMISFIRE_INSTRUCTION_FIRE_ONCE_NOW
3 j/ l" Q9 A4 c9 Y8 I
立即执行第一次misfire的操作,并且放弃其他misfire的(类似所有misfire的操作被合并执行了)。然后继续按调度执行。无论misfire多少次trigger的执行,都只会立刻执行1次。
+ n+ Q# v# j: i7 B- a6 M$ ^
例如:
& k. Z& \2 Z1 l
9点和10点的被合并执行一次(换句话说,10点需要执行的那次,被pass了)。下次执行将在11点被准时执行。
1 `! v* e7 o' a, S' @- `) M% Y, ~withMisfireHandlingInstructionDoNothing
/ a7 G) Q' Q" d9 t7 ~! F9 l+ G. n6 O0 n
MISFIRE_INSTRUCTION_DO_NOTHING
4 A) W# A& W2 v" c% `0 g所有被misfire的执行都被忽略掉,调度器会像平时一样等待下次调度。
. d' Q7 f1 z$ }; E E: A5 }0 J% }
例如:
, `# a0 \0 U8 z# m9 ~2 Z$ F- n9点和10点的被忽略掉,好像什么都没发生一样。下次执行将在11点被执行。
. f* i. O1 v- k3 ?2 C 1 s& f2 N8 z4 {: G
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/ G7 Y0 Q2 F% O
@! M' B; G% q; X3 G D; V' R
如你所有,根据实际的设定,不同的trigger会有不同的行为。此外,虽然它提供了smart policy(明智的决策),但是真正使用时,还是要取决于业务需求。
( z1 {6 P* K1 V+ l
从本质上看,主要有三种策略:忽略,立即运行然后继续正常执行,忽略misfire的并等待下次执行。( 原文: ignore, run immediately and continue and discard and wait for next. )
5 U2 A7 [7 ]+ V8 G5 M0 ^5 X
它们有不同的应用场景:
; \" o5 ?' @" }! I9 C当你需要确保每次调度任务都要被执行的时候,即时它意味着多个misfire的trigger会被触发,那么用ignore policies。试想一下,有一个任务,需要每小时,都根据上一小时的订单去生成报表。如果服务被关闭了8个小时,那你可能仍然是尽快得到那些报表的。这种情况下,配置ignore policies,调度器会尽快将那8小时的调度任务运行一遍的。尽管晚了几个小时,但是仍然是被执行了(最终报告到手了。^_^)。
! p) \: m) e0 Y2 T当你需要任务被定期执行,并且当出现misfire的情况后立即运行一次的时候,那么使用now* policies。试想一下,一个任务是每分钟清空文件夹 /tmp。如果调度器在20分钟内繁忙,最后终于可以执行这个任务了,那么你肯定不会希望它执行20次的!一次就足够了,但是要尽快执行。而后,再回到正常的执行间隔--1分钟。
, A$ Z/ o ?& V/ }- U V$ s' ~8 J/ s, M6 K
当你希望任务能在特定时间点运行的时候,使用next* policies不错。比如你需要在每个整点后15分钟抓取股票的价格。它们的变化非常快,然后现在已经整点后20分了,那么不必烦恼。你刚好错过了5分钟,但是现在你已经不在乎(那时候的价格)了。这时,一个时间间隙总好过一个不准确的值。这种情况Quartz只要跳过misfire的操作,等待下次执行就好了。
6 \7 `2 L4 T( o9 u/ }" ~' s
* w" q% g% j" Z(此文仅为作者观点,我在翻译过程中,其实也有不太明了之处,但是总体来说,还是清晰的,希望大家在以后使用工具时,也更多的关注工具的一切内在功能。)
. a' d5 o, W Q4 R
+ [& R+ `, r' O- C7 Q
) R0 p+ a2 ]) f4 F再次注明,原文地址:
http://java.dzone.com/articles/quartz-scheduler-misfire
k0 w$ }: \3 H+ h! n如转,请尊重原作者,贴上链接。
+ c0 t( Z* ^5 I9 _9 c; |6 K
7 f' Y* m) w; `+ j' j