如果你在用quartz的时候,也看到这个日志信息(Handling 2 trigger(s) that missed their scheduled fire-time.)了,并且发现quartz管理的任务,都不再被触发了,那么,你可以看看这篇文章。
- @2 U% r6 k: l1 h5 P1 K
$ N/ q. y* M% V原文地址:
http://java.dzone.com/articles/quartz-scheduler-misfire
2 U, ?. t1 y, f7 ?4 i由于本人英文水平有限,部分地方会直接用原文英语代替,另,部分翻译可能比较晦涩,望理解。
3 P4 @, K$ ^+ M1 ~" Z. X2 e1 P9 ~. l
# Q; e1 D3 \7 R8 h( T" U& y$ z* {常见词:
4 I- H5 C- F. F6 q, l' P$ ?' \6 d
misfire
http://fanyi.baidu.com/#en/zh/misfire 以下统一用misfire,汉语无法贴切表达
8 s2 M$ E% Z6 I. P3 w$ r; Smisfire instruction 失火(没启动起来后的)指示
& v0 I! I% p, j; Gsmart policy,明智的决策
% g [1 Q1 d: |5 B0 V2 X, \7 bmisfired 失火了,没启动起来的意思
$ Y8 g( `! X: P. C: s" @
worker thread 工作线程,辅助线程
! ^( {. M1 P: g: P$ @" O9 H
& C, O: `, [7 k" N. s
【翻译】
5 J8 J4 r5 |, u% B. Y3 }4 |
有时候,Quartz并不能如你所愿的运行你的job。这里有3个原因:
5 v. V$ b: m" X2 n% _: l3 D! D, {
1.所有的woker thread(工作线程; 辅助线程)都在运行其他的job
" i/ k7 m/ E8 ?4 X2.scheduler(调度器)down了(关于这个down。我不太明确是shutdown了。。还是挂掉了。因此下文依旧用down。)
5 @8 v0 c( F6 l( n ~3.任务被安排在过去的某一时刻启动(此可能为代码错误)
. @' K- _/ i, z; T. h' Z0 D
( o V4 ]1 ~6 o) b3 [) 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,汉语无法贴切表达)。
. B: m, w. ?: C% w
你知道当这种情况发生的时候,Quartz能做些什么吗? 其实,Quartz有许多的策略(叫misfire instructions,失火指示)可以处理问题,并且当你没有去想这方面问题的时候,它也有许多默认策略。但是为了使你的应用更加稳定和可预测(尤其是在高负载和可维护性上),你应该有意识的去确保triggers 和 jobs工作正常。
4 T7 c/ Z4 S* r2 R4 f' s- M
基于你用的trigger,会有不同的配置选项(对misfire instructions有效)。当然,不同的trigger也会使Quartz有不同的行为(叫做smart policy,明智的决策)。尽管文档中有misfire instructions的描述,但是我发现都很难理解它所想表达的意思,因此,我写下这篇简短的总结。
7 s+ e4 S; i8 K; i; }& U
在我深入细节之前,还有一个配置需要说明下:org.quartz.jobStore.misfireThreshold(毫秒级),默认是60000(一分钟)。它定义了trigger被认为是misfired了的时限。
" n! F* U8 ^! W0 \) l4 B2 X6 a基于默认配置,如果trigger应该在30秒以前被触发,那么很愉快地,Quartz就把它搞定了。这种延迟(delay)不能叫失火。
0 d2 y* X i# U% J
然而当trigger被发现,延迟了61秒时,那么专门的“失火处理者(misfire handler thread)”就会按照misfire instructions去处理它了。
1 a! F, r2 H% f6 h
为了测试效果,我们将这个时间设置为1000(即1秒),这样就能很快的测试“失火”了。
. Y# c1 v% L. w7 `3 C I
- o" Y/ \* {/ L& h
# q; n' v) Y- ~5 f第一个例子,是一个不需要重复触发的普通trigger,我们来看看普通trigger调度器是怎么处理“失火”,并让它运行一次的:
$ t; r, @+ h# |
【原文:Simple trigger without repeating In our first example we will see how misfiring is handled by simple triggers scheduled to run only once:】
4 X0 |8 Z6 P& g k8 @view sourceprint?
! z; l# Y! T# }8 |9 ^
1.val trigger = newTrigger().
" U/ q! X3 H, Y$ [5 N' q
2.startAt(DateUtils.addSeconds(new Date(), -10)).
6 _. \6 M& i/ \3.build()
/ w _9 g. Y8 G' B6 X' d& P, p* |( w, x) B
1 x, M3 J7 z/ F9 Z; M同样的trigger,但是明确设置了misfire instruction handler(失火处理者):
" D$ B# \( j4 f B/ }view sourceprint?
- T- o: h9 }' Y9 l$ l
1.val trigger = newTrigger().
5 e$ y1 u& x! n2.startAt(DateUtils.addSeconds(new Date(), -10)).
/ s: a2 u( z2 j' g% E9 `2 \' q3.withSchedule(
' P4 Q4 }6 _1 v
4.simpleSchedule().
6 D: E+ j# M7 M3 k+ `5.withMisfireHandlingInstructionFireNow() //MISFIRE_INSTRUCTION_FIRE_NOW
' _! w& O" J( n# K6.).
/ v% o- V7 \9 w u3 z7.build()
* [( s, \8 N+ D9 G& L$ D) M2 N4 U o
/ t. ]+ Z9 F0 Q7 O6 ^5 w# y
# g1 t, e: v, J* t3 I; D# Z为了测试,我将trigger设置为10秒前被调度(即当创建后,就已经晚于启动时间10秒)。在实际使用时,我们基本上永远不会这么设置。
^& K1 f0 f5 O' o$ S5 m J7 D换句话说,如果我们正确的设置了trigger,但是当需要被调度的时候,调度器down了或者没有空闲的worker thread了。那么,Quartz怎么处理这种extraordinary(罕见,古怪)的情况呢?
% R; a& G' [8 t' _4 s9 Z在第一段代码中,没有设置misfire instruction(so called smart policy is used in that case 这句不太会翻译。。。。)。
( f2 C" n1 U# L. t$ Z4 E* r+ ?8 a! c第二段代码中,明确指定了当misfire发生时,我们希望采取的行为。
K- s7 K7 @ ~1 R) m$ m
来看下表:
, r. {5 x# P6 s( {( M) P; b& V2 V' T: A1 Q5 J5 r0 F8 L
指令 Instruction 意义 Meaning
; a$ m& v" R9 ]6 H5 k, C8 H: Nsmart policy - default See: withMisfireHandlingInstructionFireNow
, \) i0 D. e) p* a! @, e: ~withMisfireHandlingInstructionFireNow
4 W' B. `: [/ v J, J; [MISFIRE_INSTRUCTION_FIRE_NOW 调度器发现misfire情况后,立即执行job。
+ t$ j+ b9 @0 J& C5 ~* z8 o7 ?2 P这是smart policy。
& Z: q# j) G# {7 Z3 E( O6 J& h例如:
8 Q8 u/ M0 }9 n- {8 n( n
你让一些系统清理功能在2点执行。但是很不幸,应用在那段时间由于维护,关闭了,直到3点才恢复。这样trigger就misfire了,然后调度器会尝试修复这种情况,在3点启动后,尽快执行。
- O1 H( ^6 Q6 B2 H' q3 @7 W) G
withMisfireHandlingInstructionIgnoreMisfires
4 n/ W% C N6 j! ?7 ]
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY See: withMisfireHandlingInstructionFireNow
( [0 l. l9 K9 y/ ]: |# N+ ZwithMisfireHandlingInstructionNextWithExistingCount
* O5 ~' {. s! w- ~' v# tMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT See: withMisfireHandlingInstructionNextWithRemainingCount
* ]# r0 y- ^ O; N* u
withMisfireHandlingInstructionNextWithRemainingCount
1 N% m4 `4 i& ]+ ^; q7 DMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 什么都不做。misfire被忽略了,并且没有后续的执行。当你想要彻底放弃被misfire的执行时,可以使用这个指令。
. ~& b7 w6 U" P( x! K* v# {2 C例如:
0 t* a$ U/ k% S6 N l6 d+ H0 utrigger是要启动录制一个电视节目。但是被misfire了,2个小时候,才发现。
5 Q" J0 r! ]' c【PS: 这个不是太理解,只是按照原文翻译过来,如果要用,请自行测试。。。】
; l4 ~- J0 E- D) wwithMisfireHandlingInstructionNowWithExistingCount
) \* w- M+ L- t$ |- G
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT See: withMisfireHandlingInstructionFireNow
; l( s3 O( t* K- J
withMisfireHandlingInstructionNowWithRemainingCount
4 s& S$ I/ b* F8 d, `" fMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT See: withMisfireHandlingInstructionFireNow
% I: A/ N$ t }0 A# m+ }' V
" P2 O# M' X; n) T8 ~3 x8 f, E k) g; q- }: h7 i3 _! P
普通trigger重复执行指定次数。这种情形更加复杂。想象一下,我们有一些需要重复执行指定次数的job:
/ E2 t8 p* U+ R9 f
view sourceprint?
! ], G9 t6 m+ m6 g5 h4 ^2 z
01.val trigger = newTrigger().
0 y8 G" Z; ?3 O; ` e/ D02.startAt(dateOf(9, 0, 0)).
( I$ D5 L+ L7 U( w; h
03.withSchedule(
; l; {# b) V) N9 i
04.simpleSchedule().
3 [& q3 C8 N- Z$ @/ f# J& z05.withRepeatCount(7).
# _" P. J% ~# {4 ^06.withIntervalInHours(1).
6 K5 m) ?6 z) r6 U/ |) x
07.WithMisfireHandlingInstructionFireNow() //or other
- u. G4 q# I2 {5 v5 U. W4 Y
08.).
% _/ i( _0 C. s7 k) v( a: Y$ h
09.build()
+ ?2 C0 V/ z- i5 v3 g/ ?7 K- l3 a
3 K" b% I+ i! m, H% @" W' ~# C$ A9 X; R& i. K) ~; }
在这个例子中,trigger从今天9点开始(startAt(dateOf(9, 0, 0)),共触发8次(第一次执行,和7次重复)。
$ l* h& _( |2 E- {. c, j
按理,最后一次执行应该在下午4点被触发。假设由于某些原因,在9点和10点调度器没有执行job,并且直到10:15才被系统发现misfire,也就是misfire了2次。这种情况下,调度器会怎么样呢?
+ w; }4 S0 q- L/ ~' m( A2 Q
指令 Instruction 意义 Meaning
. A* l9 b( g! \; l3 ksmart policy - default See:withMisfireHandlingInstructionNowWithExistingCount
0 o* u8 {* C( J6 v5 C
withMisfireHandlingInstructionFireNow
9 ?' L8 z; g: F% ]+ QMISFIRE_INSTRUCTION_FIRE_NOW See:withMisfireHandlingInstructionNowWithRemainingCount
7 j1 f3 ?: S0 a/ o) hwithMisfireHandlingInstructionIgnoreMisfires
) n$ K; q9 s7 |7 l
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY 尽快启动所有被启动的trigger,并将调度置为正常。
# @* V. O2 g. q1 \% z
例如:
- ^+ a9 W( ]( n# q; ~! |在我们上面的例子中,调度器会立即执行9点和10点的任务,并等待11点时,继续按正常的调度执行。
% z4 R* t& n8 ^4 X; ?备注:当处理misfire时,我们同样要注意到,实际job执行的时间,已经滞后于应该执行的时间。这意味着,你不能简单地的依赖当前系统时间,而是应该使用 JobExecutionContext .getScheduledFireTime()去获取。
0 ?4 K7 d, C1 d. k+ c
view sourceprint?
: j) H$ ~9 e" q9 F; }$ D
1.def execute(context: JobExecutionContext) {
3 e! A6 s5 M: T" V
2.val date = context.getScheduledFireTime
, x! B% S, Z, o
3.//...
/ Y5 d; w0 B$ L) e/ i9 W4.}
. w0 d6 Z; H. Z8 {3 H8 ` ~
$ |0 R1 S; A7 x5 Q. W/ w
" L5 Y$ h" J9 T8 D3 z$ h" gwithMisfireHandlingInstructionNextWithExistingCount
, l5 J% A8 j6 b" K" [$ O) u" y1 C
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT 调度器不会马上有反应。它会等待下一次执行,然后根据应该调度次数去运行trigger。
. B, {3 ]( n, E9 D
See also: withMisfireHandlingInstructionNextWithRemainingCount
3 `- z ~* n- `例如:
& x4 s4 R, R$ h8 p
在10点15发现2次misfire。调度器会等到11点,继续执行,并会每小时执行1次,共执行8次调度操作,直到下午6点停止(本该4点停止的。)
7 S# n& X$ I$ P' f2 b$ {
withMisfireHandlingInstructionNextWithRemainingCount
@3 v9 u+ b, nMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 调度器会抛弃被misfire的操作,然后等待下次执行。这样,执行的总次数,就会小于配置的次数。
/ R# r2 s4 x# F9 N
例如:在10点15,2次misfire的执行都被丢弃了。调度器会等到下个执行时间-11点,然后继续触发其余的trigger,直到4点。事实上,这种情况就像misfire从未发生过一样。
4 ~1 @9 `- t+ t* F* v$ t& G
withMisfireHandlingInstructionNowWithExistingCount
! k" \3 v# i* [; `: h
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
% E. J% r7 d; F4 X; ]) n( }第一次misfire的trigger会立即执行,而后会按设置的间隔,依次执行剩余的trigger。实际上,就像misfire的trigger的第一次触发时间,被平移到了当前时间。
# E; n7 `( Y$ _例如:
" B; k9 G$ z- u% U( f+ y( z
调度器会在10点15第一次运行misfire的trigger,然后隔1个小时,在11点15执行第二次。共执行8次,最后一次,在下午5点15。
; @8 m1 a C3 e- G3 x; Q
9 j5 u: a6 B, X( r: o- OwithMisfireHandlingInstructionNowWithRemainingCount
# a2 c( q8 N; g8 J o, t' i y5 t4 PMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
; q W1 z; T G
第一次misfire的操作,被立即执行。其余被misfire的操作,会被抛弃。
# j% v3 v6 L3 y! c
剩余没有被misfire的trigger,会按固定间隔被触发。
2 e t2 T# I4 `# ]7 O' o% l例如:
% I& c3 C( T* y7 Q0 y; [( |
调度器会在10点15运行第一次被misfire的操作(9点的。)。然后,它抛弃其余被misfire的(10点那一次)。最后,它会等1小时继续触发6个trigger:
7 m0 w4 {; t2 v+ [9 f" a11:15,12:15.... 4:15 PM。
8 M8 e1 C$ J/ i2 T, }( T+ p. v2 `4 K" _
) c% @: f% \. B( b4 p" `8 g% z# @
这是一个基于指定间隔、并重复无数次的trigger:
& F0 c0 \& X6 W3 h/ Y9 v' [view sourceprint?
$ R9 X9 H3 N/ w' D2 Y4 _- P
01.val trigger = newTrigger().
9 \# t/ \" z1 T8 @6 D* T
02.startAt(dateOf(9, 0, 0)).
3 j$ d n! x' V4 c8 S
03.withSchedule(
. z, j: Y8 |. Y- z7 _/ }$ h/ X04.simpleSchedule().
; r. q. O& r( N y05.withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY).
9 n. ]& t* [' G/ R
06.withIntervalInHours(1).
% y) ]3 R1 q( _1 W9 f* N07.WithMisfireHandlingInstructionFireNow() //or other
, N+ ~2 Y6 r) k' O: o( T6 M5 p# U
08.).
" |* l9 X3 B4 v$ j& i+ Y
09.build()
0 v/ p( h' S- |7 _0 M k- u; w6 Y* }+ D
9 }7 z: q) r j+ v( V, `- M) @
trigger应该从今天9点开始(startAt(dateOf(9, 0, 0)),每隔小时触发一次。然而调度器在9点到10点都没有执行job(比如关闭了系统、线程不够等等。。前面有介绍),并且在10点15时才被发现,misfire了2次。这种情况比那种执行执行次数的trigger更加普遍。
" v; Z% K o& [4 F, H指令 Instruction 意义 Meaning
1 @* U- m8 P. n. L) J
smart policy - default See:withMisfireHandlingInstructionNowWithExistingCount
# @5 d ]0 w' fwithMisfireHandlingInstructionFireNow
- I5 B7 U+ ~! w
MISFIRE_INSTRUCTION_FIRE_NOW See: withMisfireHandlingInstructionNowWithRemainingCount
& c# U1 ]7 p: @$ y; @' @withMisfireHandlingInstructionIgnoreMisfires
! c4 X8 y1 l% h; R
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
1 M6 ^; [- C, E8 N
https://jira.terracotta.org/jira/browse/QTZ-283
4 e9 i; R# e- G调度器会立即执行所有misfire的trigger,然后继续正常调度。
8 `! \( A3 D# h
例如:
8 b) m% Q8 X) Y) I3 D" w9点和10点的trigger会立即执行,下次执行将按计划执行(下一次是11点执行)。
0 y! [+ I9 ]' ~( _9 @: p" F4 x( @6 e! m8 Q% _5 e
withMisfireHandlingInstructionNextWithExistingCount
7 i8 u! |7 J/ G- u$ ]7 l- P
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT See:withMisfireHandlingInstructionNextWithRemainingCount
# s# R9 Y4 a( _withMisfireHandlingInstructionNextWithRemainingCount
# ~# E2 h" |! y% GMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
, o) G& [" A8 V- Z不做任何事情,misfire的情况被忽略掉。然后,调度器按设置的间隔等待下次执行。
; E1 L8 G/ ]8 e5 a D8 r: z
例如:
' _* q) `) j' @( C9点和10点misfire的执行被忽略掉。第一次执行会在11点会开始。
/ H/ v8 j% ] ]: IExample scenario: Misfired execution at 9 and 10 AM are discarded. The first execution occurs at 11 AM.
6 Z& f' P' W3 w& b3 Y* @
/ P7 a: r }; C/ ^# e- Q4 ]
withMisfireHandlingInstructionNowWithExistingCount
5 l& A( y9 X1 J0 QMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
0 r o! H, h' ~6 g3 P9 cSee:withMisfireHandlingInstructionNowWithRemainingCount
- D9 i |$ T% s, B- I
withMisfireHandlingInstructionNowWithRemainingCount
7 t/ b& ^' j6 @/ r
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
8 f" J2 ?% c; k& p
" z; p% V6 R8 e+ U" K& S. |# W7 k- b
: W- B! y7 }" v6 S& _" l4 k
第一次misfire的执行会被立即运行,其余的被忽略。下次执行会在设置的间隔时间后被触发。实际上,就是第一次执行被推迟到了当前时间。
0 g8 L3 B' E% f# h" `/ O例如:
7 u8 v+ `6 C) U r' v
调度器在10点15立即执行misfire的trigger,然后等待一个小时后,在11点15时,执行第二次。以后会每隔一小时。
2 P( _0 C. Z: K, L F
. Z3 R( G3 F. g9 o! ~1 C- q/ u
3 k) q/ P% f6 t1 Y3 z' v% Y定时触发 CRON trigger
8 j# o7 {! s0 L+ |) ?
定时触发是Quartz中最常见的。它有另外两个有效的trigger:DailyTimeIntervalTrigger(比如每25分钟一次)和CalendarIntervalTrigger(比如5个月执行一次)。They support triggering policies not possible in both CRON and simple triggers.(不会译- -!),但是他们和CRON trigger一样,支持同样的misfire handling instructions(失火处理指令)。
# r$ o; ?! _' X: B- u Qview sourceprint?
2 F3 A* Z ^* R
1.val trigger = newTrigger().
8 `# S _6 L! [6 E- e2.withSchedule(
; f a' a# {9 I F- `3.cronSchedule("0 0 9-17 ? * MON-FRI").
' X' o" a/ x- L+ S4.withMisfireHandlingInstructionFireAndProceed() //or other
+ |0 k$ H1 Y* |5 o
5.).
8 y" ]# s0 a- N) V5 _. l6 n! |
6.build()
& ?2 a/ P; @+ g! R L
; k4 G; k$ Z1 o& Z
: ]) x6 c3 N1 F这个例子是,trigger在每周一到周五的早上9点到下午5点间,每小时被触发一次。但是两次触发被misfire了,并且在10点15时,才发现这个情况。请注意,他们的失火指令效果与普通trigger是不同的:
" m L' k4 \* c" T# }5 Q P指令 Instruction 意义 Meaning
! |, Y0 U' f& h: A4 p$ psmart policy - default See: withMisfireHandlingInstructionFireAndProceed
3 r- f# D" b( w
withMisfireHandlingInstructionIgnoreMisfires
9 U( @! o6 S( T* [* H. M, E
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
2 r: y1 `2 B' J* x0 ihttps://jira.terracotta.org/jira/browse/QTZ-283
+ ^4 M5 X+ F. R4 ~( a2 M所有被misfire的执行会被立即执行,然后按照正常调度继续执行trigger。
W; }. p2 t3 S4 B* r0 t9 y
例如:
1 H% E8 r" z5 Q! t- J. f9点和10点的执行(misfire的2个)被立即执行,下次执行将在11点被准时执行。
' P$ z$ Q; ?. t: l. ]. W! hwithMisfireHandlingInstructionFireAndProceed
6 H% C1 Z/ D# r5 \" B b2 ]: ]. O& ~MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
: f+ S& P/ f& n6 x立即执行第一次misfire的操作,并且放弃其他misfire的(类似所有misfire的操作被合并执行了)。然后继续按调度执行。无论misfire多少次trigger的执行,都只会立刻执行1次。
B3 `3 H5 f S例如:
4 W6 m% Z$ |5 q1 c/ k( K# V
9点和10点的被合并执行一次(换句话说,10点需要执行的那次,被pass了)。下次执行将在11点被准时执行。
& R- g9 C- S+ i, X8 Z. S) l# qwithMisfireHandlingInstructionDoNothing
$ m$ A/ l7 |" V" _4 @/ i6 l. qMISFIRE_INSTRUCTION_DO_NOTHING
+ u9 j% f3 T) p- v0 O' G& L7 w
所有被misfire的执行都被忽略掉,调度器会像平时一样等待下次调度。
X' l5 h! A; X2 R3 Z z$ K" U7 z6 V
例如:
2 W2 _' J+ |' h( f9点和10点的被忽略掉,好像什么都没发生一样。下次执行将在11点被执行。
1 X- a/ D" V& N1 B
( @5 n( a4 B! P+ }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,关注下。)
# C# a! s+ K4 ^& ~6 `$ S
# q/ W( z( m' o
如你所有,根据实际的设定,不同的trigger会有不同的行为。此外,虽然它提供了smart policy(明智的决策),但是真正使用时,还是要取决于业务需求。
9 `/ I% ^$ z8 h e# @8 O( |' z' W5 ~$ U从本质上看,主要有三种策略:忽略,立即运行然后继续正常执行,忽略misfire的并等待下次执行。( 原文: ignore, run immediately and continue and discard and wait for next. )
; e5 b0 R: S) R) {4 i4 U* y它们有不同的应用场景:
$ V( O% b# c! o B7 ]! t当你需要确保每次调度任务都要被执行的时候,即时它意味着多个misfire的trigger会被触发,那么用ignore policies。试想一下,有一个任务,需要每小时,都根据上一小时的订单去生成报表。如果服务被关闭了8个小时,那你可能仍然是尽快得到那些报表的。这种情况下,配置ignore policies,调度器会尽快将那8小时的调度任务运行一遍的。尽管晚了几个小时,但是仍然是被执行了(最终报告到手了。^_^)。
" V, D/ q3 K' q2 `当你需要任务被定期执行,并且当出现misfire的情况后立即运行一次的时候,那么使用now* policies。试想一下,一个任务是每分钟清空文件夹 /tmp。如果调度器在20分钟内繁忙,最后终于可以执行这个任务了,那么你肯定不会希望它执行20次的!一次就足够了,但是要尽快执行。而后,再回到正常的执行间隔--1分钟。
9 O" W4 @! o& Z4 G
当你希望任务能在特定时间点运行的时候,使用next* policies不错。比如你需要在每个整点后15分钟抓取股票的价格。它们的变化非常快,然后现在已经整点后20分了,那么不必烦恼。你刚好错过了5分钟,但是现在你已经不在乎(那时候的价格)了。这时,一个时间间隙总好过一个不准确的值。这种情况Quartz只要跳过misfire的操作,等待下次执行就好了。
, M4 t: S# z) I( I
, d; ?7 ?! d/ T(此文仅为作者观点,我在翻译过程中,其实也有不太明了之处,但是总体来说,还是清晰的,希望大家在以后使用工具时,也更多的关注工具的一切内在功能。)
8 b$ c N: Q8 K3 [2 E# {
% A+ s1 P' h5 u5 C6 J" l* T
( u p/ K0 H Q3 j+ F再次注明,原文地址:
http://java.dzone.com/articles/quartz-scheduler-misfire
+ F' g8 E }2 ?5 ~2 D如转,请尊重原作者,贴上链接。
; m7 L3 G8 m& b0 @* U
5 a, B# X2 \* z% Q- L$ u- f5 z9 V% R