如果你在用quartz的时候,也看到这个日志信息(Handling 2 trigger(s) that missed their scheduled fire-time.)了,并且发现quartz管理的任务,都不再被触发了,那么,你可以看看这篇文章。
3 U) {( K* {$ y+ W, }3 D
v W) x, x! u3 v. G5 c原文地址:
http://java.dzone.com/articles/quartz-scheduler-misfire
$ M- T7 k4 }) e由于本人英文水平有限,部分地方会直接用原文英语代替,另,部分翻译可能比较晦涩,望理解。
# g P7 d' R- o1 B
8 {, P4 [" X: R( U; i- |常见词:
0 H1 H2 I; t6 D; h0 ]; Y- b- I% P5 M% b7 S
misfire
http://fanyi.baidu.com/#en/zh/misfire 以下统一用misfire,汉语无法贴切表达
+ N8 q; q6 p8 q5 K3 M5 l9 Gmisfire instruction 失火(没启动起来后的)指示
7 t; V/ m4 R0 r. v, W, a, e
smart policy,明智的决策
; P4 m+ b$ `' c/ l5 N( V/ p" N
misfired 失火了,没启动起来的意思
$ |+ g/ L; O$ P" N( }# O: o5 ?
worker thread 工作线程,辅助线程
3 B& U ?) ~8 V: N$ D( r% R6 l5 ~3 l0 k1 g3 O( m% N
【翻译】
& B! @/ A' T" \
有时候,Quartz并不能如你所愿的运行你的job。这里有3个原因:
Y' e+ O8 o; q, g1.所有的woker thread(工作线程; 辅助线程)都在运行其他的job
4 W; G6 F0 t \7 M- r1 g N
2.scheduler(调度器)down了(关于这个down。我不太明确是shutdown了。。还是挂掉了。因此下文依旧用down。)
; o4 u B, I9 u; y! E- t! Q5 K3.任务被安排在过去的某一时刻启动(此可能为代码错误)
: A# z% }: C; Y! f0 @+ E
) f7 r) F9 ?0 y8 `, N9 K
你可以简单地通过配置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,汉语无法贴切表达)。
: n4 X {( A0 k) Y; ~; R E
你知道当这种情况发生的时候,Quartz能做些什么吗? 其实,Quartz有许多的策略(叫misfire instructions,失火指示)可以处理问题,并且当你没有去想这方面问题的时候,它也有许多默认策略。但是为了使你的应用更加稳定和可预测(尤其是在高负载和可维护性上),你应该有意识的去确保triggers 和 jobs工作正常。
8 S0 P% z. H Y
基于你用的trigger,会有不同的配置选项(对misfire instructions有效)。当然,不同的trigger也会使Quartz有不同的行为(叫做smart policy,明智的决策)。尽管文档中有misfire instructions的描述,但是我发现都很难理解它所想表达的意思,因此,我写下这篇简短的总结。
( M5 G0 H' w0 }在我深入细节之前,还有一个配置需要说明下:org.quartz.jobStore.misfireThreshold(毫秒级),默认是60000(一分钟)。它定义了trigger被认为是misfired了的时限。
$ F9 d4 X/ b5 y& X, {" K
基于默认配置,如果trigger应该在30秒以前被触发,那么很愉快地,Quartz就把它搞定了。这种延迟(delay)不能叫失火。
0 I( z- q% Z8 z/ T! R, }3 J然而当trigger被发现,延迟了61秒时,那么专门的“失火处理者(misfire handler thread)”就会按照misfire instructions去处理它了。
* M( ]' J0 t. |/ O) }/ B. U
为了测试效果,我们将这个时间设置为1000(即1秒),这样就能很快的测试“失火”了。
) E+ R6 e# G. ? j9 Z" b
' @7 v- Z& _# K4 }
; e3 r, h" x$ B1 b" [, H" U+ X
第一个例子,是一个不需要重复触发的普通trigger,我们来看看普通trigger调度器是怎么处理“失火”,并让它运行一次的:
+ g; c/ {1 g' Y【原文:Simple trigger without repeating In our first example we will see how misfiring is handled by simple triggers scheduled to run only once:】
3 Z( u3 ^2 w3 W k+ [8 U. K$ ]
view sourceprint?
/ V1 N2 _% q8 V1.val trigger = newTrigger().
: s3 Q4 ~; h- X& \! E$ t/ H3 l
2.startAt(DateUtils.addSeconds(new Date(), -10)).
6 ]- s }3 X) u9 a% O3.build()
1 w6 n$ i0 m+ I! C+ ^' @
) _2 U" b6 @8 t/ k
3 g1 `! Y9 R5 {; f
同样的trigger,但是明确设置了misfire instruction handler(失火处理者):
0 |3 r2 J* J, p# [9 u; oview sourceprint?
# K; h% I4 j2 J+ J& ^6 |
1.val trigger = newTrigger().
! q2 R' x6 S: w# K. r: M3 N
2.startAt(DateUtils.addSeconds(new Date(), -10)).
& J7 E& \9 l: F3.withSchedule(
3 e" f R1 }9 P8 I: \
4.simpleSchedule().
" J2 q4 h: j& u$ w7 T' R" P5.withMisfireHandlingInstructionFireNow() //MISFIRE_INSTRUCTION_FIRE_NOW
. E* V5 E) o: X2 l6 N+ t
6.).
6 b: m0 Q4 k0 [7 ?
7.build()
/ q, C q+ x# c/ ^5 j/ F: h3 @ G# _
' V$ V+ Q% k2 A1 \
6 l- }* p; B+ f S$ {为了测试,我将trigger设置为10秒前被调度(即当创建后,就已经晚于启动时间10秒)。在实际使用时,我们基本上永远不会这么设置。
7 x {6 \ U. p p; _& O6 z! g. `换句话说,如果我们正确的设置了trigger,但是当需要被调度的时候,调度器down了或者没有空闲的worker thread了。那么,Quartz怎么处理这种extraordinary(罕见,古怪)的情况呢?
0 [2 P% E2 C9 s5 O! }; w3 P i- f
在第一段代码中,没有设置misfire instruction(so called smart policy is used in that case 这句不太会翻译。。。。)。
) b! p' v& u2 _
第二段代码中,明确指定了当misfire发生时,我们希望采取的行为。
/ [& l0 C& G5 G0 R q* {% L来看下表:
: z/ x# J2 C" S* {
2 c, s# g% y) d( i" B U; }指令 Instruction 意义 Meaning
* r2 {5 d% i, o1 B, r4 [; k1 w
smart policy - default See: withMisfireHandlingInstructionFireNow
2 d8 n* R0 \+ b6 k& G
withMisfireHandlingInstructionFireNow
# P$ ^( u1 l- E) c4 c( t7 E5 G6 eMISFIRE_INSTRUCTION_FIRE_NOW 调度器发现misfire情况后,立即执行job。
8 S3 A6 t. W' u: `; ~) ^1 D6 x9 ?
这是smart policy。
+ v/ i5 P9 t# e例如:
% q$ _- E8 Y! ]. \0 D i
你让一些系统清理功能在2点执行。但是很不幸,应用在那段时间由于维护,关闭了,直到3点才恢复。这样trigger就misfire了,然后调度器会尝试修复这种情况,在3点启动后,尽快执行。
5 H% |) G" E% U2 [8 swithMisfireHandlingInstructionIgnoreMisfires
- W2 U' R, d8 r- w7 _# S
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY See: withMisfireHandlingInstructionFireNow
. Y% t+ t) ~9 Y5 {
withMisfireHandlingInstructionNextWithExistingCount
2 ?: N' W; k0 V
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT See: withMisfireHandlingInstructionNextWithRemainingCount
/ P- N+ d7 w/ h; w" c
withMisfireHandlingInstructionNextWithRemainingCount
" [! I2 g. ^' pMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 什么都不做。misfire被忽略了,并且没有后续的执行。当你想要彻底放弃被misfire的执行时,可以使用这个指令。
* h( p. ^ ^6 C& v2 `. p0 h
例如:
! T3 M% F6 G) p, C
trigger是要启动录制一个电视节目。但是被misfire了,2个小时候,才发现。
1 e2 E. e3 T) y, I& S8 M! p) u【PS: 这个不是太理解,只是按照原文翻译过来,如果要用,请自行测试。。。】
- A* } Z4 W! a* I' f
withMisfireHandlingInstructionNowWithExistingCount
0 x# D* Y% g% a- m$ ]/ u1 \; k
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT See: withMisfireHandlingInstructionFireNow
% E# N% x. f1 ~5 C$ h N) TwithMisfireHandlingInstructionNowWithRemainingCount
! E$ d1 I& s1 a6 m; t
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT See: withMisfireHandlingInstructionFireNow
4 A9 n% V, V- t8 j. N' `& A' k4 n" \- ^" X) f
' F& D' f; ~0 K$ S4 { W普通trigger重复执行指定次数。这种情形更加复杂。想象一下,我们有一些需要重复执行指定次数的job:
3 T" K; H" |+ T% C$ w) Dview sourceprint?
& b8 R9 s" x& z% ~" O O01.val trigger = newTrigger().
+ c5 `: p$ n( i0 r- t/ V7 p3 u
02.startAt(dateOf(9, 0, 0)).
5 v3 a+ G z! {2 K+ m* i03.withSchedule(
1 m/ n8 J/ ^; E/ D$ w
04.simpleSchedule().
; x8 E7 G4 {% }. {! j U
05.withRepeatCount(7).
6 @' p' l* \; P7 J" S8 D0 {' [, P06.withIntervalInHours(1).
: ?: J4 u$ R: m: A% A0 J
07.WithMisfireHandlingInstructionFireNow() //or other
! U. x* \6 J& A8 O08.).
9 U2 e2 ?& Q! a L$ V
09.build()
+ Y6 q4 c; N3 A: E6 l* a
8 i6 f0 x/ A2 v# X
7 Y4 w3 v. |6 m5 v6 C2 `. ^. U在这个例子中,trigger从今天9点开始(startAt(dateOf(9, 0, 0)),共触发8次(第一次执行,和7次重复)。
( ^/ P+ D9 U* }按理,最后一次执行应该在下午4点被触发。假设由于某些原因,在9点和10点调度器没有执行job,并且直到10:15才被系统发现misfire,也就是misfire了2次。这种情况下,调度器会怎么样呢?
. w9 o. t5 J5 f2 C1 \) M, O7 U
指令 Instruction 意义 Meaning
0 X+ \7 J# q% \$ ]8 O, _, Jsmart policy - default See:withMisfireHandlingInstructionNowWithExistingCount
1 V) n; n. I+ T) b: H7 R
withMisfireHandlingInstructionFireNow
5 j3 _& d9 W4 T5 L! s: mMISFIRE_INSTRUCTION_FIRE_NOW See:withMisfireHandlingInstructionNowWithRemainingCount
( T5 ^" Q! h2 ~2 C$ p$ p& Q9 qwithMisfireHandlingInstructionIgnoreMisfires
5 K" j& S. o0 z. RMISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY 尽快启动所有被启动的trigger,并将调度置为正常。
; ]0 B2 t% I) A$ r
例如:
2 s- j# }. s5 B5 B0 x. O( V" G
在我们上面的例子中,调度器会立即执行9点和10点的任务,并等待11点时,继续按正常的调度执行。
+ A9 Z; f! @- i0 ?1 S4 f, [
备注:当处理misfire时,我们同样要注意到,实际job执行的时间,已经滞后于应该执行的时间。这意味着,你不能简单地的依赖当前系统时间,而是应该使用 JobExecutionContext .getScheduledFireTime()去获取。
& X% i* w9 L" T% X8 Lview sourceprint?
8 n1 K1 ~3 ?3 \# ]) m
1.def execute(context: JobExecutionContext) {
2 T1 S$ Q7 Z6 Q
2.val date = context.getScheduledFireTime
6 v4 p o8 B# J& q) n
3.//...
7 @) e1 w/ K% \. N4.}
' @: s% M- ?) p$ k f% E4 {
) J2 p* Q; l$ A K
' O$ Q0 K: U$ ^( I9 awithMisfireHandlingInstructionNextWithExistingCount
4 D5 k. u, t. f6 d7 ZMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT 调度器不会马上有反应。它会等待下一次执行,然后根据应该调度次数去运行trigger。
- s) f2 U3 }& ^8 L0 D
See also: withMisfireHandlingInstructionNextWithRemainingCount
2 g2 J) @9 [' P5 B
例如:
% c9 L7 ?! y5 \% k6 V7 t4 u在10点15发现2次misfire。调度器会等到11点,继续执行,并会每小时执行1次,共执行8次调度操作,直到下午6点停止(本该4点停止的。)
$ T& k1 ^% I" N! FwithMisfireHandlingInstructionNextWithRemainingCount
+ J. e, i8 c; g9 F
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 调度器会抛弃被misfire的操作,然后等待下次执行。这样,执行的总次数,就会小于配置的次数。
. N7 m g" b0 D! ^# W' t' C# N例如:在10点15,2次misfire的执行都被丢弃了。调度器会等到下个执行时间-11点,然后继续触发其余的trigger,直到4点。事实上,这种情况就像misfire从未发生过一样。
$ M8 a0 R% g+ E3 m3 SwithMisfireHandlingInstructionNowWithExistingCount
9 N+ h; I: a: ~% |: D6 Z5 W+ V6 oMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
- C. H( ]: V" f8 w- d: n第一次misfire的trigger会立即执行,而后会按设置的间隔,依次执行剩余的trigger。实际上,就像misfire的trigger的第一次触发时间,被平移到了当前时间。
3 q/ l5 f3 i( z例如:
) `7 t N) j# U/ O8 |- t
调度器会在10点15第一次运行misfire的trigger,然后隔1个小时,在11点15执行第二次。共执行8次,最后一次,在下午5点15。
7 P- g+ V ?; ^1 q* F* Y1 o
% K; [" p k- C" e+ H% ~+ y
withMisfireHandlingInstructionNowWithRemainingCount
1 n8 J5 R& i- c& ~7 HMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
/ R# _4 ^0 R6 b+ d4 Z# Z第一次misfire的操作,被立即执行。其余被misfire的操作,会被抛弃。
* ]; L+ M# j) {; K- O
剩余没有被misfire的trigger,会按固定间隔被触发。
0 X3 {# s# w5 G0 M5 o
例如:
2 [% P) T4 J6 p7 u, h( S7 R
调度器会在10点15运行第一次被misfire的操作(9点的。)。然后,它抛弃其余被misfire的(10点那一次)。最后,它会等1小时继续触发6个trigger:
( _* A# X) p, o
11:15,12:15.... 4:15 PM。
9 J6 }0 H8 ~3 V5 ]! I
( B- r- F* P) @3 J' J4 T& ]& X4 G3 ~' |- V& }
这是一个基于指定间隔、并重复无数次的trigger:
1 {$ x: J* _- W8 _, v
view sourceprint?
; U6 _* p% R9 \. J! o) d& B- _
01.val trigger = newTrigger().
# I l9 H+ o' l' U+ [02.startAt(dateOf(9, 0, 0)).
0 W& O" V0 {, l9 h2 p/ t* M% K03.withSchedule(
5 Y( [5 ]6 @5 d C
04.simpleSchedule().
( O1 Y- K9 {! p3 d9 P! u05.withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY).
: d+ y5 G0 X ^. D" [1 _( R3 _! v06.withIntervalInHours(1).
( _; H/ i6 m1 S5 \9 D0 ^1 |07.WithMisfireHandlingInstructionFireNow() //or other
E- F* L1 ]& ~+ a9 q! k! ~
08.).
0 G; k! Q* N0 y( M& V& b, @09.build()
# ^& T4 F. y' v& h% J, y" k) I+ A% {6 Y9 y! v7 o
/ o- ?. {' a. u
trigger应该从今天9点开始(startAt(dateOf(9, 0, 0)),每隔小时触发一次。然而调度器在9点到10点都没有执行job(比如关闭了系统、线程不够等等。。前面有介绍),并且在10点15时才被发现,misfire了2次。这种情况比那种执行执行次数的trigger更加普遍。
% e6 z; K9 O* {) {( @( h2 U
指令 Instruction 意义 Meaning
+ I% o2 k4 D a: \8 P3 m D! Y
smart policy - default See:withMisfireHandlingInstructionNowWithExistingCount
( _( z3 ^3 G. i" N. Y' U
withMisfireHandlingInstructionFireNow
8 A% x+ A& ?% q2 G' E: l
MISFIRE_INSTRUCTION_FIRE_NOW See: withMisfireHandlingInstructionNowWithRemainingCount
3 V& F7 R0 {: d; W6 r
withMisfireHandlingInstructionIgnoreMisfires
* f3 \. {7 C, i7 m8 U0 v3 L0 w
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
# g' M+ `. a% E$ Z, q) z2 Z- S; I
https://jira.terracotta.org/jira/browse/QTZ-2836 S w0 u2 _0 ^! E5 K
调度器会立即执行所有misfire的trigger,然后继续正常调度。
# ^3 z7 e! s$ }/ e0 d
例如:
/ f8 J; M, I: ?6 B
9点和10点的trigger会立即执行,下次执行将按计划执行(下一次是11点执行)。
7 |3 X4 m2 R1 x' E8 {* J4 @
7 v4 @+ ^ k/ l& p& s& Q4 _withMisfireHandlingInstructionNextWithExistingCount
S* h3 i( l! R* K. ?6 k
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT See:withMisfireHandlingInstructionNextWithRemainingCount
( t; S( q2 c G! b) [1 x2 i. k
withMisfireHandlingInstructionNextWithRemainingCount
* G# Z1 y: x6 D" {' m4 ]
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
4 m8 V% m) |6 T- h& f% c3 H/ Z1 }( E
不做任何事情,misfire的情况被忽略掉。然后,调度器按设置的间隔等待下次执行。
" g8 [9 x8 n4 G& H
例如:
- c0 S7 [, h6 d3 m- H, r
9点和10点misfire的执行被忽略掉。第一次执行会在11点会开始。
! T% O" R- i4 {& ]( N# V" x
Example scenario: Misfired execution at 9 and 10 AM are discarded. The first execution occurs at 11 AM.
q& o+ w" D, ~
; M& r3 `. P6 i6 iwithMisfireHandlingInstructionNowWithExistingCount
! F# u2 A% m" b8 e
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
& y r' z, k0 C8 S. _/ ^
See:withMisfireHandlingInstructionNowWithRemainingCount
4 |: v' h( y( T) e1 x
withMisfireHandlingInstructionNowWithRemainingCount
, ^4 E% C! V0 k) ^MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
6 B: q7 I# Y0 y( T" f. }9 F; g8 A( J; b# j! v2 I4 w9 p
5 p: N0 v: n1 k, U
第一次misfire的执行会被立即运行,其余的被忽略。下次执行会在设置的间隔时间后被触发。实际上,就是第一次执行被推迟到了当前时间。
* s6 Y, |* L/ G
例如:
2 f2 m4 ]9 E) `8 }; W0 v6 b
调度器在10点15立即执行misfire的trigger,然后等待一个小时后,在11点15时,执行第二次。以后会每隔一小时。
- P! f1 `8 `6 Q/ E! G* Z! u0 g1 F
# U% c( u0 d6 m- l) J定时触发 CRON trigger
( S; [- v6 W' U' m- w1 A. A' c m
定时触发是Quartz中最常见的。它有另外两个有效的trigger:DailyTimeIntervalTrigger(比如每25分钟一次)和CalendarIntervalTrigger(比如5个月执行一次)。They support triggering policies not possible in both CRON and simple triggers.(不会译- -!),但是他们和CRON trigger一样,支持同样的misfire handling instructions(失火处理指令)。
+ Z$ r% A' h! y A
view sourceprint?
; A7 c& \' z A+ r+ w
1.val trigger = newTrigger().
0 v5 e1 S" ^( e2.withSchedule(
6 X- t2 M( E8 P9 w) \( j5 l3.cronSchedule("0 0 9-17 ? * MON-FRI").
, u( h2 g, ?9 t5 f/ W9 o6 i4 i
4.withMisfireHandlingInstructionFireAndProceed() //or other
- [& ]) ?2 n+ U7 u
5.).
+ I. I5 ]3 ]1 |, w- Y- i# W1 l
6.build()
: q6 j+ U' q/ P: e4 `
/ p/ _* q4 Y* A/ q; d
4 |# Z1 ^% U- K/ Y; q; ^ B这个例子是,trigger在每周一到周五的早上9点到下午5点间,每小时被触发一次。但是两次触发被misfire了,并且在10点15时,才发现这个情况。请注意,他们的失火指令效果与普通trigger是不同的:
6 M( J* f" h: S C5 j5 \
指令 Instruction 意义 Meaning
2 O. c: y7 N" I# ^# F: {4 T& N
smart policy - default See: withMisfireHandlingInstructionFireAndProceed
- d; D. j4 M/ k0 K. ~2 }& t5 U" @
withMisfireHandlingInstructionIgnoreMisfires
+ z' h" T( h6 A2 `MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
5 E8 K( O7 T* U3 R8 mhttps://jira.terracotta.org/jira/browse/QTZ-283
3 _4 C. P9 K8 M6 ^( P/ p9 ?所有被misfire的执行会被立即执行,然后按照正常调度继续执行trigger。
' g {3 a& \$ ^+ F _- B: A例如:
) l# d. ~4 _' E! J. I' I9点和10点的执行(misfire的2个)被立即执行,下次执行将在11点被准时执行。
6 K6 ^' {3 Z3 V/ U9 |withMisfireHandlingInstructionFireAndProceed
* A; p/ a# O+ Y( v+ z' j( e* b2 hMISFIRE_INSTRUCTION_FIRE_ONCE_NOW
/ F1 f- `2 `" }% h5 L# k, S6 @. F5 g
立即执行第一次misfire的操作,并且放弃其他misfire的(类似所有misfire的操作被合并执行了)。然后继续按调度执行。无论misfire多少次trigger的执行,都只会立刻执行1次。
g5 ~0 o% S; ?. p例如:
. s: D1 W) ]0 M" R" o5 V
9点和10点的被合并执行一次(换句话说,10点需要执行的那次,被pass了)。下次执行将在11点被准时执行。
. @& Y7 R$ ^5 r/ g/ b
withMisfireHandlingInstructionDoNothing
( v% O7 i* f5 sMISFIRE_INSTRUCTION_DO_NOTHING
2 J6 D7 F. B% t! k( j& ~6 s所有被misfire的执行都被忽略掉,调度器会像平时一样等待下次调度。
. ^' k" m! m& v. ~( j1 |& {* o' Z% l- Y5 F
例如:
0 W# t, D6 C/ n/ L, I: s9 R7 d! [
9点和10点的被忽略掉,好像什么都没发生一样。下次执行将在11点被执行。
' u" r$ f& E0 G4 c6 z) S2 z6 C
; @4 [+ p" M0 c- h' ~" p( NQTZ-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,关注下。)
0 t( C! b' `8 V- _ j- F& H
# f1 Z! ?0 @$ _8 p4 H* L$ b& z如你所有,根据实际的设定,不同的trigger会有不同的行为。此外,虽然它提供了smart policy(明智的决策),但是真正使用时,还是要取决于业务需求。
$ {) [/ t# U% m) K1 w' A( Z
从本质上看,主要有三种策略:忽略,立即运行然后继续正常执行,忽略misfire的并等待下次执行。( 原文: ignore, run immediately and continue and discard and wait for next. )
& J+ Y: y- [ L# k$ k
它们有不同的应用场景:
0 K" e/ W5 l, @! u$ |
当你需要确保每次调度任务都要被执行的时候,即时它意味着多个misfire的trigger会被触发,那么用ignore policies。试想一下,有一个任务,需要每小时,都根据上一小时的订单去生成报表。如果服务被关闭了8个小时,那你可能仍然是尽快得到那些报表的。这种情况下,配置ignore policies,调度器会尽快将那8小时的调度任务运行一遍的。尽管晚了几个小时,但是仍然是被执行了(最终报告到手了。^_^)。
$ E: S! A, K. _3 G6 u6 C5 m: `3 |6 Z
当你需要任务被定期执行,并且当出现misfire的情况后立即运行一次的时候,那么使用now* policies。试想一下,一个任务是每分钟清空文件夹 /tmp。如果调度器在20分钟内繁忙,最后终于可以执行这个任务了,那么你肯定不会希望它执行20次的!一次就足够了,但是要尽快执行。而后,再回到正常的执行间隔--1分钟。
# W! [3 T& G' G" l& a$ w2 r
当你希望任务能在特定时间点运行的时候,使用next* policies不错。比如你需要在每个整点后15分钟抓取股票的价格。它们的变化非常快,然后现在已经整点后20分了,那么不必烦恼。你刚好错过了5分钟,但是现在你已经不在乎(那时候的价格)了。这时,一个时间间隙总好过一个不准确的值。这种情况Quartz只要跳过misfire的操作,等待下次执行就好了。
, j# ?: N7 g) Y S# b* I& v
# ]0 j$ ?5 C. X5 U
(此文仅为作者观点,我在翻译过程中,其实也有不太明了之处,但是总体来说,还是清晰的,希望大家在以后使用工具时,也更多的关注工具的一切内在功能。)
4 N6 ?* K8 c9 r t( o' p& J* k* k" J: o$ R% z; D
% `1 k- k% n. U$ I K6 E; J
再次注明,原文地址:
http://java.dzone.com/articles/quartz-scheduler-misfire- E4 E5 Q7 m9 [
如转,请尊重原作者,贴上链接。
. l( q0 z& {1 w
5 w" z2 ?+ ~ _& x7 x* {2 N( f