如果你在用quartz的时候,也看到这个日志信息(Handling 2 trigger(s) that missed their scheduled fire-time.)了,并且发现quartz管理的任务,都不再被触发了,那么,你可以看看这篇文章。
7 Y7 _) w; s7 ?9 R* E9 d& |% J0 B
2 c8 N: O# u Z原文地址:
http://java.dzone.com/articles/quartz-scheduler-misfire
/ k9 H+ I& `9 o7 d7 U$ d5 J+ I) {由于本人英文水平有限,部分地方会直接用原文英语代替,另,部分翻译可能比较晦涩,望理解。
i! G& K7 u$ X' P2 s' X
% @7 P+ f: p6 Z$ z% f
常见词:
/ Z% L# L9 N0 X6 F8 }! |4 X
misfire
http://fanyi.baidu.com/#en/zh/misfire 以下统一用misfire,汉语无法贴切表达
3 ?) b' z A6 Q& N1 \misfire instruction 失火(没启动起来后的)指示
5 E% x, d% F% Q) w, s1 K: j$ h+ h
smart policy,明智的决策
$ H9 Y( d4 K' g, s6 J7 smisfired 失火了,没启动起来的意思
- v. V7 I/ p4 _; b4 U: H+ o4 H4 g3 jworker thread 工作线程,辅助线程
& E: H$ K! U* O- D- K. A: v
; U5 H6 g" q7 b4 [) X1 g D
【翻译】
7 |' U) z V" {, f有时候,Quartz并不能如你所愿的运行你的job。这里有3个原因:
% @) F; k3 y4 N3 \
1.所有的woker thread(工作线程; 辅助线程)都在运行其他的job
/ W) Q! w l' X, K3 Z3 t2.scheduler(调度器)down了(关于这个down。我不太明确是shutdown了。。还是挂掉了。因此下文依旧用down。)
$ P: l" _/ O' a6 ~/ D6 S6 _
3.任务被安排在过去的某一时刻启动(此可能为代码错误)
7 Y' l8 J8 k) F$ [6 g' h6 m; w" ^* I
你可以简单地通过配置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,汉语无法贴切表达)。
4 f2 {- W+ a' L. B X5 l# d你知道当这种情况发生的时候,Quartz能做些什么吗? 其实,Quartz有许多的策略(叫misfire instructions,失火指示)可以处理问题,并且当你没有去想这方面问题的时候,它也有许多默认策略。但是为了使你的应用更加稳定和可预测(尤其是在高负载和可维护性上),你应该有意识的去确保triggers 和 jobs工作正常。
, K: r) C r7 ^# K9 i
基于你用的trigger,会有不同的配置选项(对misfire instructions有效)。当然,不同的trigger也会使Quartz有不同的行为(叫做smart policy,明智的决策)。尽管文档中有misfire instructions的描述,但是我发现都很难理解它所想表达的意思,因此,我写下这篇简短的总结。
0 |# B6 W/ d6 t( d在我深入细节之前,还有一个配置需要说明下:org.quartz.jobStore.misfireThreshold(毫秒级),默认是60000(一分钟)。它定义了trigger被认为是misfired了的时限。
7 O" F' u2 d" c$ Q: |9 i基于默认配置,如果trigger应该在30秒以前被触发,那么很愉快地,Quartz就把它搞定了。这种延迟(delay)不能叫失火。
7 X/ H9 r# j+ K q3 Z% D然而当trigger被发现,延迟了61秒时,那么专门的“失火处理者(misfire handler thread)”就会按照misfire instructions去处理它了。
5 g1 s/ m! y" J5 O0 t' n为了测试效果,我们将这个时间设置为1000(即1秒),这样就能很快的测试“失火”了。
+ ?, o+ k6 H& l$ F5 W
8 H) C2 W& ~; i/ O# T+ x" ^
: n/ q, ?/ S/ t" H7 q: `3 M' }' W第一个例子,是一个不需要重复触发的普通trigger,我们来看看普通trigger调度器是怎么处理“失火”,并让它运行一次的:
y+ V9 j! \. _8 Z- R6 Z. M7 @【原文:Simple trigger without repeating In our first example we will see how misfiring is handled by simple triggers scheduled to run only once:】
/ l1 s7 v, ~0 ]
view sourceprint?
1 Z/ `% w) O: H2 z& D8 L) f1.val trigger = newTrigger().
" T4 r+ `7 t0 E% V, s2.startAt(DateUtils.addSeconds(new Date(), -10)).
5 I3 U) ?* ^; K4 i. C- y6 ]
3.build()
* T( H S1 a O1 B
! J4 ~* K( r0 u0 N3 j1 `7 [/ g
$ x/ d3 t2 k* |同样的trigger,但是明确设置了misfire instruction handler(失火处理者):
- `. M, u) X. D& t5 Lview sourceprint?
4 H! O0 S- W' c5 d; {1.val trigger = newTrigger().
+ a; o$ |" c7 }, \8 @2.startAt(DateUtils.addSeconds(new Date(), -10)).
Q: I, l$ l7 ?9 p- r, j
3.withSchedule(
- L6 X- D# s* p- @4.simpleSchedule().
9 t* Z/ x, g) F; s- b& ^4 t
5.withMisfireHandlingInstructionFireNow() //MISFIRE_INSTRUCTION_FIRE_NOW
$ M# K8 I2 o* \3 i/ s6.).
9 e6 ~; I. W5 f3 q, k( Y; Y
7.build()
* w) Z9 d( F/ u- R" Z) P
0 P. G n. O' C% C' \8 ?
; D" h$ e0 m& W# k) P
为了测试,我将trigger设置为10秒前被调度(即当创建后,就已经晚于启动时间10秒)。在实际使用时,我们基本上永远不会这么设置。
* u/ t2 r# Q* M2 k( K- |换句话说,如果我们正确的设置了trigger,但是当需要被调度的时候,调度器down了或者没有空闲的worker thread了。那么,Quartz怎么处理这种extraordinary(罕见,古怪)的情况呢?
5 x5 V% d" `/ e. l在第一段代码中,没有设置misfire instruction(so called smart policy is used in that case 这句不太会翻译。。。。)。
- O% y8 J0 X7 E0 W) Z
第二段代码中,明确指定了当misfire发生时,我们希望采取的行为。
% q2 b, Z2 [: r G9 q. F8 c
来看下表:
: H; G1 D: `" Z
& o' Z+ x# @3 @' y- e指令 Instruction 意义 Meaning
2 c3 e1 ?" u7 q d' S, h
smart policy - default See: withMisfireHandlingInstructionFireNow
/ J" x) Z" v* b: V- k* q( |* S# HwithMisfireHandlingInstructionFireNow
3 y6 j1 X1 C2 T; {3 w, e
MISFIRE_INSTRUCTION_FIRE_NOW 调度器发现misfire情况后,立即执行job。
5 v: g: Y9 v9 Y) m; g这是smart policy。
- d* }! K, X, q; D+ Y1 S例如:
* E' g" W$ ~2 i K/ R# l- d
你让一些系统清理功能在2点执行。但是很不幸,应用在那段时间由于维护,关闭了,直到3点才恢复。这样trigger就misfire了,然后调度器会尝试修复这种情况,在3点启动后,尽快执行。
2 `3 p Y9 V f" @7 r% c
withMisfireHandlingInstructionIgnoreMisfires
$ {" l( ^- a0 T$ Q' X# P
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY See: withMisfireHandlingInstructionFireNow
: q2 r1 q& m A4 V- a A L r6 \. O; WwithMisfireHandlingInstructionNextWithExistingCount
! Q3 w* {( r( q, d3 {3 R% S# F
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT See: withMisfireHandlingInstructionNextWithRemainingCount
% i! i+ V6 D/ O8 V
withMisfireHandlingInstructionNextWithRemainingCount
8 p' m/ a8 G6 l, h% gMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 什么都不做。misfire被忽略了,并且没有后续的执行。当你想要彻底放弃被misfire的执行时,可以使用这个指令。
2 m1 F% E3 W* m5 k
例如:
, o! O! ]/ ]+ x; e4 S; w
trigger是要启动录制一个电视节目。但是被misfire了,2个小时候,才发现。
& b/ N* Q% g; x2 s( R【PS: 这个不是太理解,只是按照原文翻译过来,如果要用,请自行测试。。。】
9 U5 l# p7 _2 E5 ^
withMisfireHandlingInstructionNowWithExistingCount
1 v) p. A. w9 H$ M: I; e1 mMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT See: withMisfireHandlingInstructionFireNow
" ^7 Z# C, @2 o5 jwithMisfireHandlingInstructionNowWithRemainingCount
x' X) q% ~1 X( q$ V$ A
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT See: withMisfireHandlingInstructionFireNow
" m: \' P( _1 ~( P0 d
4 ~+ J: L6 }3 E( j( Z* h
3 L( K! E# a7 x' w
普通trigger重复执行指定次数。这种情形更加复杂。想象一下,我们有一些需要重复执行指定次数的job:
, Z) e- x- O( H
view sourceprint?
4 _3 m! `9 k- U ]01.val trigger = newTrigger().
9 w' @) s) j5 M- A% Q
02.startAt(dateOf(9, 0, 0)).
8 \1 C+ ?# P1 I4 H# i+ C- M( V03.withSchedule(
. G- I- c c( _# h# z- W
04.simpleSchedule().
% v) s: Q# i6 \! s5 T9 p
05.withRepeatCount(7).
: s- }/ r* C; ?+ \06.withIntervalInHours(1).
/ }' H+ W! J1 o* V5 P! z
07.WithMisfireHandlingInstructionFireNow() //or other
* T% Z, L5 ~& s. ^* W
08.).
: O3 u8 L4 k1 B& j09.build()
2 r! J3 z. X9 R6 W1 u a( V# ^2 @( p# J* a4 U% Y. ~, x' A
* E+ b6 U" L. r; m5 B2 D, l) S在这个例子中,trigger从今天9点开始(startAt(dateOf(9, 0, 0)),共触发8次(第一次执行,和7次重复)。
& b: C) Y4 P g" j按理,最后一次执行应该在下午4点被触发。假设由于某些原因,在9点和10点调度器没有执行job,并且直到10:15才被系统发现misfire,也就是misfire了2次。这种情况下,调度器会怎么样呢?
4 J$ J" ]5 }' z4 f1 u/ k2 c指令 Instruction 意义 Meaning
( b0 a! `( l2 p( h
smart policy - default See:withMisfireHandlingInstructionNowWithExistingCount
' e: }# {# q7 A9 r) I6 KwithMisfireHandlingInstructionFireNow
' q( c1 F# V) X' |0 A& S0 A
MISFIRE_INSTRUCTION_FIRE_NOW See:withMisfireHandlingInstructionNowWithRemainingCount
6 c* G: \0 o7 O6 ^9 {; l* r: A
withMisfireHandlingInstructionIgnoreMisfires
: ~% i) \5 z# |1 G3 C& C
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY 尽快启动所有被启动的trigger,并将调度置为正常。
3 p1 }( U, ]3 O- i% X# u _例如:
% ?2 a2 `3 ?- g6 u, z4 M. U6 S% N
在我们上面的例子中,调度器会立即执行9点和10点的任务,并等待11点时,继续按正常的调度执行。
9 _& }8 B3 }% ]" D( ^, ?2 |+ r备注:当处理misfire时,我们同样要注意到,实际job执行的时间,已经滞后于应该执行的时间。这意味着,你不能简单地的依赖当前系统时间,而是应该使用 JobExecutionContext .getScheduledFireTime()去获取。
4 C& F# Y& s5 i# C0 I, Xview sourceprint?
3 Y, d( u6 o0 @2 g1.def execute(context: JobExecutionContext) {
R2 i! u% P' a& I2.val date = context.getScheduledFireTime
; y8 q; s D$ n. s( b- F3.//...
0 O1 R3 Y4 s" g6 `% S
4.}
& E4 \8 w) D2 _9 J; \% Y G
" q4 X/ |; t( @. U% R7 t& p8 b. M4 y" q
withMisfireHandlingInstructionNextWithExistingCount
4 S" F% g8 s) y6 i# |. o E, |MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT 调度器不会马上有反应。它会等待下一次执行,然后根据应该调度次数去运行trigger。
. @; `* i8 _) m- ~, V% s# T
See also: withMisfireHandlingInstructionNextWithRemainingCount
1 J6 U. e/ A0 G5 C6 _- R5 j
例如:
# s, f' |1 {+ Z' s在10点15发现2次misfire。调度器会等到11点,继续执行,并会每小时执行1次,共执行8次调度操作,直到下午6点停止(本该4点停止的。)
! H: {9 V1 [% Z) H
withMisfireHandlingInstructionNextWithRemainingCount
% z1 a! U4 x# K. F _9 F7 W! O' h1 r
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 调度器会抛弃被misfire的操作,然后等待下次执行。这样,执行的总次数,就会小于配置的次数。
/ J+ t! ^6 a' y( x2 q例如:在10点15,2次misfire的执行都被丢弃了。调度器会等到下个执行时间-11点,然后继续触发其余的trigger,直到4点。事实上,这种情况就像misfire从未发生过一样。
8 O* f2 D+ j1 a2 U
withMisfireHandlingInstructionNowWithExistingCount
; h7 r& m- V% I( d* j% \
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
5 o/ h" H# j) O1 j, Q
第一次misfire的trigger会立即执行,而后会按设置的间隔,依次执行剩余的trigger。实际上,就像misfire的trigger的第一次触发时间,被平移到了当前时间。
+ Z. i; D; D8 B e" h例如:
, r% J9 o2 _) [8 _调度器会在10点15第一次运行misfire的trigger,然后隔1个小时,在11点15执行第二次。共执行8次,最后一次,在下午5点15。
, x3 X" [+ b& J: u% ^! ^
{- ^' ^" N5 _ W1 E% y
withMisfireHandlingInstructionNowWithRemainingCount
! d' Z4 A; W0 _) X. L
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
; {8 u0 _! f$ y' b2 o( B
第一次misfire的操作,被立即执行。其余被misfire的操作,会被抛弃。
& C/ D! n3 S; g/ b
剩余没有被misfire的trigger,会按固定间隔被触发。
3 c0 S* x/ h( X( @
例如:
. _1 y" c2 w, \! p6 a% `
调度器会在10点15运行第一次被misfire的操作(9点的。)。然后,它抛弃其余被misfire的(10点那一次)。最后,它会等1小时继续触发6个trigger:
# m; b0 {) q1 j4 c
11:15,12:15.... 4:15 PM。
! L4 X1 H) I' ?) R' L0 w7 `9 o2 R% W' c) x6 |" z8 @
' X. p/ y+ p: `
这是一个基于指定间隔、并重复无数次的trigger:
" e' A f7 Q& |: y) \view sourceprint?
' J7 W: y2 ]! n5 p: M' Z( {) N01.val trigger = newTrigger().
- h K; C4 R/ C+ s' P) D, n2 v4 }02.startAt(dateOf(9, 0, 0)).
7 U$ e) A2 O. X8 ]& q) i8 V
03.withSchedule(
- W/ N6 P, o! _; `6 b04.simpleSchedule().
- b4 x3 O& N7 C' u, k7 Z& o" k
05.withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY).
2 w3 ~" R, }. L. s2 O
06.withIntervalInHours(1).
( J+ y" I5 V1 T" S2 m @6 ~9 z1 ?
07.WithMisfireHandlingInstructionFireNow() //or other
/ Z$ w. k' } b. K
08.).
" m' q5 f0 U! x9 J% P. K6 W l- l09.build()
- A M+ u% ]& c
7 u* m e/ ^' U2 i
' [; Z, o( \/ t6 Mtrigger应该从今天9点开始(startAt(dateOf(9, 0, 0)),每隔小时触发一次。然而调度器在9点到10点都没有执行job(比如关闭了系统、线程不够等等。。前面有介绍),并且在10点15时才被发现,misfire了2次。这种情况比那种执行执行次数的trigger更加普遍。
7 h1 _& B: B! {
指令 Instruction 意义 Meaning
6 |$ F* N" N' c( O, T
smart policy - default See:withMisfireHandlingInstructionNowWithExistingCount
& Y4 \& C, {1 Q7 ?4 XwithMisfireHandlingInstructionFireNow
8 }. O' Y5 P; R" E ^7 h
MISFIRE_INSTRUCTION_FIRE_NOW See: withMisfireHandlingInstructionNowWithRemainingCount
6 b* F' q1 ?6 ^' t* c) c% k; I) owithMisfireHandlingInstructionIgnoreMisfires
2 y4 ?6 N, z+ P5 [
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
) t; E6 F6 q+ w( O3 khttps://jira.terracotta.org/jira/browse/QTZ-2838 r1 T4 T1 P8 p) y
调度器会立即执行所有misfire的trigger,然后继续正常调度。
# R0 p# u, L/ q [1 Q3 c9 X
例如:
( J% Q. h! |/ x, A# m5 }! t$ q& k9点和10点的trigger会立即执行,下次执行将按计划执行(下一次是11点执行)。
9 A) W8 I I5 R; [: ^. m
2 ], d- c9 A& h' VwithMisfireHandlingInstructionNextWithExistingCount
' W, P1 v& E4 Q; ^MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT See:withMisfireHandlingInstructionNextWithRemainingCount
1 O+ f; D* B7 _8 z+ k/ awithMisfireHandlingInstructionNextWithRemainingCount
) f7 e, c5 k4 aMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
5 w# X% L I$ F1 P
不做任何事情,misfire的情况被忽略掉。然后,调度器按设置的间隔等待下次执行。
% {7 v4 X9 H# T8 Y例如:
( z6 {' I; T5 k) {+ I! L! F5 R
9点和10点misfire的执行被忽略掉。第一次执行会在11点会开始。
4 c2 j" E# v# U1 C5 t4 L9 O+ g A
Example scenario: Misfired execution at 9 and 10 AM are discarded. The first execution occurs at 11 AM.
6 c2 O6 {6 }) e' M& K4 M- ^: m& R1 C6 q" F1 a F u
withMisfireHandlingInstructionNowWithExistingCount
$ R, q+ r, G( O' q f+ FMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
+ _6 y5 |# |3 U" X4 M% O8 S) {See:withMisfireHandlingInstructionNowWithRemainingCount
9 n( s. i5 c: v8 g2 }7 ?withMisfireHandlingInstructionNowWithRemainingCount
& k3 q- u( l, Y8 d! k" uMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
1 G: g2 E. ~) U/ s6 O+ c0 m3 ~ a" i4 Z7 R3 X0 w7 r+ i" ]
, s6 q/ [9 _# ]$ ~第一次misfire的执行会被立即运行,其余的被忽略。下次执行会在设置的间隔时间后被触发。实际上,就是第一次执行被推迟到了当前时间。
/ _; ?. P. l: b" V& p# z1 X6 P例如:
" ]( C F* A* D5 r
调度器在10点15立即执行misfire的trigger,然后等待一个小时后,在11点15时,执行第二次。以后会每隔一小时。
9 R/ K9 N0 ?( Q/ d! A, U1 E
1 C' q8 p' y$ `4 E, X6 w1 g* q: |8 o+ G
定时触发 CRON trigger
' F- d* F5 q8 }% f) \7 f8 E
定时触发是Quartz中最常见的。它有另外两个有效的trigger:DailyTimeIntervalTrigger(比如每25分钟一次)和CalendarIntervalTrigger(比如5个月执行一次)。They support triggering policies not possible in both CRON and simple triggers.(不会译- -!),但是他们和CRON trigger一样,支持同样的misfire handling instructions(失火处理指令)。
3 o6 M' V# X' F$ C/ F5 Pview sourceprint?
3 ?* ~; W: v5 R1.val trigger = newTrigger().
5 o+ v" ^; Y% {8 D% k
2.withSchedule(
! W# D$ \; v. v. J: Y
3.cronSchedule("0 0 9-17 ? * MON-FRI").
6 o; g) T2 Z1 j4.withMisfireHandlingInstructionFireAndProceed() //or other
: _( H+ R2 P: Y4 ~0 \5.).
) e4 i* Q3 i3 ?0 P; S& W
6.build()
9 e$ q; U" z4 \# W( q6 ^
% `2 _; R' A" R; z) P: ~
; u5 i8 c0 s, y' I7 N/ r这个例子是,trigger在每周一到周五的早上9点到下午5点间,每小时被触发一次。但是两次触发被misfire了,并且在10点15时,才发现这个情况。请注意,他们的失火指令效果与普通trigger是不同的:
" O# K$ S; J z2 e7 r C9 b* L* J指令 Instruction 意义 Meaning
+ Z( K" D( }4 ~- t8 b( n# x
smart policy - default See: withMisfireHandlingInstructionFireAndProceed
6 c2 ^& s1 o5 H
withMisfireHandlingInstructionIgnoreMisfires
7 x: z n" N) i7 C
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
I, y6 q/ i! ~; t F+ S% O4 m. Khttps://jira.terracotta.org/jira/browse/QTZ-2833 Z% @: ~$ p& ~& }
所有被misfire的执行会被立即执行,然后按照正常调度继续执行trigger。
7 n5 x& i- T6 ~; P' L. V6 y& I" `
例如:
0 Y2 ]" X1 b- T7 h' S6 f9点和10点的执行(misfire的2个)被立即执行,下次执行将在11点被准时执行。
' Y8 |, _: I$ z' U6 VwithMisfireHandlingInstructionFireAndProceed
4 _& W* N4 Z- w: u' H
MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
7 K* }3 ?% j9 m1 `, e
立即执行第一次misfire的操作,并且放弃其他misfire的(类似所有misfire的操作被合并执行了)。然后继续按调度执行。无论misfire多少次trigger的执行,都只会立刻执行1次。
/ Z! W; z; u3 Y. P4 Z5 W y
例如:
; M- |8 v; z4 F
9点和10点的被合并执行一次(换句话说,10点需要执行的那次,被pass了)。下次执行将在11点被准时执行。
) P: B6 d2 P2 i9 U2 c
withMisfireHandlingInstructionDoNothing
5 ^2 f! _( T' O* m, t: S; ]MISFIRE_INSTRUCTION_DO_NOTHING
- H/ |( y# }; k* n7 k3 v所有被misfire的执行都被忽略掉,调度器会像平时一样等待下次调度。
- j6 A! |8 g2 x4 ~$ \( L/ K
例如:
& q9 W* Y" U( Y: X+ m9点和10点的被忽略掉,好像什么都没发生一样。下次执行将在11点被执行。
( m' Y3 O, F0 ~* @. B5 d/ o
" \* Q+ Y; T( ~/ P0 m" p( gQTZ-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,关注下。)
^$ C8 v1 N1 Q0 X& Y
4 P: c; p% ^3 ^: R2 x8 m如你所有,根据实际的设定,不同的trigger会有不同的行为。此外,虽然它提供了smart policy(明智的决策),但是真正使用时,还是要取决于业务需求。
& _! W' u) o! [) F
从本质上看,主要有三种策略:忽略,立即运行然后继续正常执行,忽略misfire的并等待下次执行。( 原文: ignore, run immediately and continue and discard and wait for next. )
. f! ]+ `( d2 O8 S) P
它们有不同的应用场景:
* ]4 v/ e* \5 V- Q! [" v
当你需要确保每次调度任务都要被执行的时候,即时它意味着多个misfire的trigger会被触发,那么用ignore policies。试想一下,有一个任务,需要每小时,都根据上一小时的订单去生成报表。如果服务被关闭了8个小时,那你可能仍然是尽快得到那些报表的。这种情况下,配置ignore policies,调度器会尽快将那8小时的调度任务运行一遍的。尽管晚了几个小时,但是仍然是被执行了(最终报告到手了。^_^)。
* B8 w- _# ^2 R3 u: |! A; c9 v
当你需要任务被定期执行,并且当出现misfire的情况后立即运行一次的时候,那么使用now* policies。试想一下,一个任务是每分钟清空文件夹 /tmp。如果调度器在20分钟内繁忙,最后终于可以执行这个任务了,那么你肯定不会希望它执行20次的!一次就足够了,但是要尽快执行。而后,再回到正常的执行间隔--1分钟。
) k/ j/ Y& j6 Q8 z) @6 U当你希望任务能在特定时间点运行的时候,使用next* policies不错。比如你需要在每个整点后15分钟抓取股票的价格。它们的变化非常快,然后现在已经整点后20分了,那么不必烦恼。你刚好错过了5分钟,但是现在你已经不在乎(那时候的价格)了。这时,一个时间间隙总好过一个不准确的值。这种情况Quartz只要跳过misfire的操作,等待下次执行就好了。
% k) C# a! f# ]/ w% q; W
% E( ^. q! @ z1 C' m(此文仅为作者观点,我在翻译过程中,其实也有不太明了之处,但是总体来说,还是清晰的,希望大家在以后使用工具时,也更多的关注工具的一切内在功能。)
5 _# A( v2 A. U) l1 ` B i+ j2 N* L7 W2 ~; `! m
1 N B; f& T$ Z' e0 _7 u
再次注明,原文地址:
http://java.dzone.com/articles/quartz-scheduler-misfire
% k; j& Y3 c* z* R+ j如转,请尊重原作者,贴上链接。
9 d. W7 b- H* p
. r- b& |, _5 g( h+ A% O# V5 i