如果你在用quartz的时候,也看到这个日志信息(Handling 2 trigger(s) that missed their scheduled fire-time.)了,并且发现quartz管理的任务,都不再被触发了,那么,你可以看看这篇文章。
9 S( |# a- Q- F
# V, v5 W5 R1 [( Q" p3 b$ d& e原文地址:
http://java.dzone.com/articles/quartz-scheduler-misfire' p5 J% r( u# O
由于本人英文水平有限,部分地方会直接用原文英语代替,另,部分翻译可能比较晦涩,望理解。
8 Q# l+ C& x g$ f( [7 T
5 C! Z8 a; T; ~4 b常见词:
$ X+ m1 @6 P- s5 L: O" ~
misfire
http://fanyi.baidu.com/#en/zh/misfire 以下统一用misfire,汉语无法贴切表达
3 L! k/ P, l, k, d6 [' A Smisfire instruction 失火(没启动起来后的)指示
5 b: @. Q* \( \4 p5 |0 K8 ?( esmart policy,明智的决策
( z/ T; C H3 y8 b. Amisfired 失火了,没启动起来的意思
- B7 f- E& r9 K/ x0 J) wworker thread 工作线程,辅助线程
+ G6 x( v7 E. h( F# q, p
* m0 d* q! `" x: J, \- @; G: y$ f【翻译】
! J9 C7 @% Z( W! U t& M: s
有时候,Quartz并不能如你所愿的运行你的job。这里有3个原因:
; W3 ^+ p, Q# U% z" ?
1.所有的woker thread(工作线程; 辅助线程)都在运行其他的job
: ]( R, K, l, @: T
2.scheduler(调度器)down了(关于这个down。我不太明确是shutdown了。。还是挂掉了。因此下文依旧用down。)
8 ]4 e, |' }/ `! _# S2 V2 E3.任务被安排在过去的某一时刻启动(此可能为代码错误)
$ L" k+ U1 H5 a3 c h/ v6 S7 v
) x" A$ R0 X, w+ O
你可以简单地通过配置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,汉语无法贴切表达)。
& x# v! Q$ I4 T8 x( t
你知道当这种情况发生的时候,Quartz能做些什么吗? 其实,Quartz有许多的策略(叫misfire instructions,失火指示)可以处理问题,并且当你没有去想这方面问题的时候,它也有许多默认策略。但是为了使你的应用更加稳定和可预测(尤其是在高负载和可维护性上),你应该有意识的去确保triggers 和 jobs工作正常。
- \' I" x& e, K7 ?7 F# x% d
基于你用的trigger,会有不同的配置选项(对misfire instructions有效)。当然,不同的trigger也会使Quartz有不同的行为(叫做smart policy,明智的决策)。尽管文档中有misfire instructions的描述,但是我发现都很难理解它所想表达的意思,因此,我写下这篇简短的总结。
[5 S* R( X9 v) _% x4 W
在我深入细节之前,还有一个配置需要说明下:org.quartz.jobStore.misfireThreshold(毫秒级),默认是60000(一分钟)。它定义了trigger被认为是misfired了的时限。
/ m$ U" u9 ^! G% M6 Z基于默认配置,如果trigger应该在30秒以前被触发,那么很愉快地,Quartz就把它搞定了。这种延迟(delay)不能叫失火。
# C5 I0 \/ y" |
然而当trigger被发现,延迟了61秒时,那么专门的“失火处理者(misfire handler thread)”就会按照misfire instructions去处理它了。
% i$ R8 Y; F% P5 k* O# @
为了测试效果,我们将这个时间设置为1000(即1秒),这样就能很快的测试“失火”了。
k2 e+ V( N% }# k" Y, _6 H
2 o0 A+ Q/ G, u' e
) { G% [4 _- ?& q, p1 s9 c
第一个例子,是一个不需要重复触发的普通trigger,我们来看看普通trigger调度器是怎么处理“失火”,并让它运行一次的:
& j0 A- x3 B l" s" Q6 R
【原文:Simple trigger without repeating In our first example we will see how misfiring is handled by simple triggers scheduled to run only once:】
- T) E, u4 U# V, `# u, \9 Hview sourceprint?
7 r% m1 a) V2 v/ {. G% Y# [
1.val trigger = newTrigger().
f& Y2 W3 P: b. n) o0 ^' F
2.startAt(DateUtils.addSeconds(new Date(), -10)).
/ {) @6 ~. F/ S0 ^2 o+ X
3.build()
7 |: K( [% z# i
; E! K7 K$ g0 C. G/ L$ \
* U4 T( \9 R l* q! k0 K; W7 H8 |
同样的trigger,但是明确设置了misfire instruction handler(失火处理者):
`% N+ o9 l, Y2 R( f9 v5 [
view sourceprint?
! m- f% q( Z. R! M- z5 L
1.val trigger = newTrigger().
6 z0 W3 l6 M3 d2.startAt(DateUtils.addSeconds(new Date(), -10)).
4 \1 X' V. S; `9 j1 D7 \, N' K4 M3.withSchedule(
$ p5 m. ^: c. w# Z7 J: }; L
4.simpleSchedule().
( z' ~: H, q/ s+ q' C5.withMisfireHandlingInstructionFireNow() //MISFIRE_INSTRUCTION_FIRE_NOW
% {8 j' w% c1 [# `
6.).
7 I4 E# K7 e' g- S& m8 t
7.build()
8 Y( |: v8 M) h. W4 C8 f
: \) \! @/ Z0 v& ]. c
7 e7 ^) G2 {& S% ?' M5 P; ^
为了测试,我将trigger设置为10秒前被调度(即当创建后,就已经晚于启动时间10秒)。在实际使用时,我们基本上永远不会这么设置。
\8 p# ?& Q& a# m换句话说,如果我们正确的设置了trigger,但是当需要被调度的时候,调度器down了或者没有空闲的worker thread了。那么,Quartz怎么处理这种extraordinary(罕见,古怪)的情况呢?
: q7 D% R: {4 x9 Z
在第一段代码中,没有设置misfire instruction(so called smart policy is used in that case 这句不太会翻译。。。。)。
0 {4 y5 Y, v0 e( U+ Q2 v7 ~
第二段代码中,明确指定了当misfire发生时,我们希望采取的行为。
: m: F7 Y7 h( C
来看下表:
7 r J$ }9 R6 z3 i
! B& K6 ?3 P0 @ q2 I* @5 H; N
指令 Instruction 意义 Meaning
; Z, c0 Q& D" [/ i! o* ]0 s3 X* osmart policy - default See: withMisfireHandlingInstructionFireNow
) C' I+ F8 }5 T; fwithMisfireHandlingInstructionFireNow
- w& {8 S. w% R
MISFIRE_INSTRUCTION_FIRE_NOW 调度器发现misfire情况后,立即执行job。
- Z0 E- [, B& }6 ?- |: W这是smart policy。
! a: t9 c& y$ v( |# e
例如:
8 G% @' l, i! T4 l; q, ~
你让一些系统清理功能在2点执行。但是很不幸,应用在那段时间由于维护,关闭了,直到3点才恢复。这样trigger就misfire了,然后调度器会尝试修复这种情况,在3点启动后,尽快执行。
9 k; Q" a& i) b" P h3 m$ \: E( NwithMisfireHandlingInstructionIgnoreMisfires
2 P/ b* Z1 |% O6 T& H) C0 E% c! M0 xMISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY See: withMisfireHandlingInstructionFireNow
0 d) o/ z- y, i" I% z; T! \% YwithMisfireHandlingInstructionNextWithExistingCount
5 S% A3 d* E6 K M# sMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT See: withMisfireHandlingInstructionNextWithRemainingCount
( }: J0 J# l* y5 @$ b9 |6 S
withMisfireHandlingInstructionNextWithRemainingCount
8 j9 W) P# b( A4 b& C
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 什么都不做。misfire被忽略了,并且没有后续的执行。当你想要彻底放弃被misfire的执行时,可以使用这个指令。
5 v# N# c% t7 I* g: ]' ^2 F8 k
例如:
. a% L2 W' o9 d! U. ^$ ntrigger是要启动录制一个电视节目。但是被misfire了,2个小时候,才发现。
& L2 }- U8 E0 m* b0 p7 A g
【PS: 这个不是太理解,只是按照原文翻译过来,如果要用,请自行测试。。。】
/ D6 O+ M& F. D' t5 S
withMisfireHandlingInstructionNowWithExistingCount
f% c" m/ z/ [0 M, P
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT See: withMisfireHandlingInstructionFireNow
* L1 |! |0 w' w# b- Y9 t/ A' z8 z" Y
withMisfireHandlingInstructionNowWithRemainingCount
7 S4 s% O3 N8 n8 }" r( T
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT See: withMisfireHandlingInstructionFireNow
2 x n2 c4 N5 K) w$ f0 A6 V) L3 }% n9 Q1 y; _
+ c( Q& n# D2 `+ b. e! V
普通trigger重复执行指定次数。这种情形更加复杂。想象一下,我们有一些需要重复执行指定次数的job:
2 C) {2 n" N$ s: t
view sourceprint?
2 ~0 C Z$ b5 t! W: O8 { A' F- g4 e01.val trigger = newTrigger().
3 a3 V1 I, ^# g, C- A* n
02.startAt(dateOf(9, 0, 0)).
3 T% Q* l m9 v. \( Q; w* ?' w03.withSchedule(
' y0 N- J1 v3 I$ y04.simpleSchedule().
) g' }5 t9 ~8 p
05.withRepeatCount(7).
8 r) z ]1 W" F) [06.withIntervalInHours(1).
/ M+ h0 ?2 \5 I/ ?5 D) K& F' f
07.WithMisfireHandlingInstructionFireNow() //or other
" a5 e- c& K/ X9 G1 \
08.).
) @% }' C) E) U' x/ K3 b4 A4 Q4 i
09.build()
5 ^, W8 b1 N% I9 x9 ^: }0 K7 R8 R W" `4 ~6 T) J
' P+ C; L$ z, n q/ O在这个例子中,trigger从今天9点开始(startAt(dateOf(9, 0, 0)),共触发8次(第一次执行,和7次重复)。
* X4 j% I4 R, \按理,最后一次执行应该在下午4点被触发。假设由于某些原因,在9点和10点调度器没有执行job,并且直到10:15才被系统发现misfire,也就是misfire了2次。这种情况下,调度器会怎么样呢?
$ c3 i- w" u; {' v3 |指令 Instruction 意义 Meaning
, e1 H4 C, A' @0 m" usmart policy - default See:withMisfireHandlingInstructionNowWithExistingCount
% a( g; f) B% p# `6 z+ _9 F
withMisfireHandlingInstructionFireNow
, A) t, Q& s6 ?3 T3 Z
MISFIRE_INSTRUCTION_FIRE_NOW See:withMisfireHandlingInstructionNowWithRemainingCount
5 L% w+ F* n* j( Q3 O. p
withMisfireHandlingInstructionIgnoreMisfires
( e3 B, H) Y& UMISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY 尽快启动所有被启动的trigger,并将调度置为正常。
: y+ p- x9 b: Z6 `) \例如:
7 ~, j! Z( C! B. c* u8 I; m
在我们上面的例子中,调度器会立即执行9点和10点的任务,并等待11点时,继续按正常的调度执行。
% R- v! d/ d _- N+ {# \. b备注:当处理misfire时,我们同样要注意到,实际job执行的时间,已经滞后于应该执行的时间。这意味着,你不能简单地的依赖当前系统时间,而是应该使用 JobExecutionContext .getScheduledFireTime()去获取。
& G. l! M: s( U4 S/ s: g; @view sourceprint?
( y/ ?6 d0 {: R0 M) K1.def execute(context: JobExecutionContext) {
4 C3 d6 j# t4 m/ ~- e# f4 z7 E
2.val date = context.getScheduledFireTime
( g2 g; I* T5 X, ^& q0 m+ s0 T
3.//...
$ S* e' L6 l0 {; w0 N: L, x4.}
& T4 I; i+ u& r2 c1 O" R) a
$ ?! V+ {: p, Q( C# f/ R0 y
# e7 f4 _/ X4 \; ?: Z QwithMisfireHandlingInstructionNextWithExistingCount
) b& D/ D q$ S% F5 Z9 rMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT 调度器不会马上有反应。它会等待下一次执行,然后根据应该调度次数去运行trigger。
) V+ \- D3 Q1 t0 c( H; y
See also: withMisfireHandlingInstructionNextWithRemainingCount
( K! \5 n; |% H2 u% i例如:
) v. d) A9 M: _0 f
在10点15发现2次misfire。调度器会等到11点,继续执行,并会每小时执行1次,共执行8次调度操作,直到下午6点停止(本该4点停止的。)
( _ _- `$ x, |; ^
withMisfireHandlingInstructionNextWithRemainingCount
5 B1 s! K% K* s# A! `1 t$ | e; AMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 调度器会抛弃被misfire的操作,然后等待下次执行。这样,执行的总次数,就会小于配置的次数。
& l6 {1 P! z+ H; L, s
例如:在10点15,2次misfire的执行都被丢弃了。调度器会等到下个执行时间-11点,然后继续触发其余的trigger,直到4点。事实上,这种情况就像misfire从未发生过一样。
/ _5 ]7 D; L3 S6 j6 }2 g; [
withMisfireHandlingInstructionNowWithExistingCount
/ J" I: Q+ f" {: E6 y8 E1 rMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
$ Y3 I7 y+ {* n# _$ m
第一次misfire的trigger会立即执行,而后会按设置的间隔,依次执行剩余的trigger。实际上,就像misfire的trigger的第一次触发时间,被平移到了当前时间。
* W& c7 y6 u# o0 n c
例如:
8 f6 I# K, v5 Z1 m' E' r
调度器会在10点15第一次运行misfire的trigger,然后隔1个小时,在11点15执行第二次。共执行8次,最后一次,在下午5点15。
# R5 V$ Z/ g5 Y/ y7 J G/ f# [' c8 M9 p, m
withMisfireHandlingInstructionNowWithRemainingCount
+ q7 w: A3 m' u9 PMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
2 g) _( j, w. `8 I
第一次misfire的操作,被立即执行。其余被misfire的操作,会被抛弃。
+ U3 i* e# ` V/ Z e7 }7 u4 D, D
剩余没有被misfire的trigger,会按固定间隔被触发。
{) z2 ?6 P% {6 h8 a M2 A例如:
' T' Y/ D8 H; ~8 g8 u; N
调度器会在10点15运行第一次被misfire的操作(9点的。)。然后,它抛弃其余被misfire的(10点那一次)。最后,它会等1小时继续触发6个trigger:
& D% V7 y, @7 B S
11:15,12:15.... 4:15 PM。
$ e2 i8 \* O) V9 U
2 k* r" m6 o$ `
2 B9 `4 r4 r I( I* B7 Z# X1 L1 T
这是一个基于指定间隔、并重复无数次的trigger:
. u" f7 m( x! dview sourceprint?
4 U: _! p0 s6 Q! s
01.val trigger = newTrigger().
* l. Z" L# g& J
02.startAt(dateOf(9, 0, 0)).
$ Q4 ?! O0 d5 P, x0 R% E03.withSchedule(
" e4 t0 H" ]0 ]% t6 c4 C7 h04.simpleSchedule().
4 K, C$ d$ G; l4 T) Z+ s
05.withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY).
( i( y Q* T- H! e% [( b
06.withIntervalInHours(1).
! @- j4 y9 Z7 ~3 U5 B4 ?. @07.WithMisfireHandlingInstructionFireNow() //or other
: Q! i9 W; Y& Y! M/ l n3 m u+ I
08.).
# H+ ] v$ W& }09.build()
; b2 {4 H" x. i5 y( q
6 _; D: ]. @ {9 e8 ?+ o
8 g4 e& r5 M( r' i( Itrigger应该从今天9点开始(startAt(dateOf(9, 0, 0)),每隔小时触发一次。然而调度器在9点到10点都没有执行job(比如关闭了系统、线程不够等等。。前面有介绍),并且在10点15时才被发现,misfire了2次。这种情况比那种执行执行次数的trigger更加普遍。
' c/ ^+ ~ E2 h2 d指令 Instruction 意义 Meaning
/ n! P* y0 |; z0 T, m9 w- q
smart policy - default See:withMisfireHandlingInstructionNowWithExistingCount
9 l- [+ `7 [9 W( u% E4 Q9 }: }
withMisfireHandlingInstructionFireNow
6 ^) u& {$ _0 H
MISFIRE_INSTRUCTION_FIRE_NOW See: withMisfireHandlingInstructionNowWithRemainingCount
8 b' y# U" F. E$ I5 {
withMisfireHandlingInstructionIgnoreMisfires
, L/ v; l( S; W& d+ O
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
' \ n1 ?7 L* k; S. Z# S8 M0 _2 b
https://jira.terracotta.org/jira/browse/QTZ-2838 [1 [$ F7 w, A, m0 y$ |" _
调度器会立即执行所有misfire的trigger,然后继续正常调度。
Y$ A+ `* W" I- h8 \( g( I5 F9 E
例如:
. \' q8 ]+ l: P [9点和10点的trigger会立即执行,下次执行将按计划执行(下一次是11点执行)。
) a. ` ^( o! N! x3 A& H& ?) r
withMisfireHandlingInstructionNextWithExistingCount
( c% \/ G! q3 ` H" u
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT See:withMisfireHandlingInstructionNextWithRemainingCount
' ~7 l) d( Q) l5 F( w
withMisfireHandlingInstructionNextWithRemainingCount
" ]/ i. l8 y6 \" f5 D. g% w, @MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
1 E' @% s% ?9 Y# d& {不做任何事情,misfire的情况被忽略掉。然后,调度器按设置的间隔等待下次执行。
7 t5 b. {: F* f1 T
例如:
" I8 q" p$ w3 x' E- Y ~
9点和10点misfire的执行被忽略掉。第一次执行会在11点会开始。
8 p+ f% T0 v4 E4 d& q. ?Example scenario: Misfired execution at 9 and 10 AM are discarded. The first execution occurs at 11 AM.
) C% a$ ]- _) `0 F4 b* H; h! ?, y
: h) p7 h' R% a/ g0 JwithMisfireHandlingInstructionNowWithExistingCount
1 z/ {& B! u1 R# OMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
- F5 B j" v6 C" S# W+ E; Q0 z9 SSee:withMisfireHandlingInstructionNowWithRemainingCount
, R; m3 t e2 t2 I" L! z5 F8 N/ C
withMisfireHandlingInstructionNowWithRemainingCount
* ]. x$ L Z, A& V7 VMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
5 w4 K/ C7 j8 Y; y
6 \3 z, ~; z% Q) E
5 x( N. I6 `& b第一次misfire的执行会被立即运行,其余的被忽略。下次执行会在设置的间隔时间后被触发。实际上,就是第一次执行被推迟到了当前时间。
# s$ M, F* I& G# t! {* ~' T例如:
5 Y4 }- Q* T0 p* w/ W调度器在10点15立即执行misfire的trigger,然后等待一个小时后,在11点15时,执行第二次。以后会每隔一小时。
9 p5 m2 h9 f, O4 r+ ^: w d E9 D$ B5 p1 n) m `" J& U1 {
# t7 h& r- p i6 d; i
定时触发 CRON trigger
$ x X" }3 Q6 C0 ?3 t% F9 E$ J定时触发是Quartz中最常见的。它有另外两个有效的trigger:DailyTimeIntervalTrigger(比如每25分钟一次)和CalendarIntervalTrigger(比如5个月执行一次)。They support triggering policies not possible in both CRON and simple triggers.(不会译- -!),但是他们和CRON trigger一样,支持同样的misfire handling instructions(失火处理指令)。
, B5 R( `. O1 w1 n. W9 dview sourceprint?
/ [, J2 I) i" H6 A) {" g7 u4 i8 m+ ~
1.val trigger = newTrigger().
( _8 S- t6 m0 a5 ~
2.withSchedule(
# W5 m# |0 o9 y5 A" ?5 h3.cronSchedule("0 0 9-17 ? * MON-FRI").
8 X" b% f, N ~" ~# [0 F5 C/ [
4.withMisfireHandlingInstructionFireAndProceed() //or other
$ ]# H- E' \* `) W* M. W5.).
0 S" L9 G5 l: L4 Y0 l X. Z, b8 U* ?6 T* @
6.build()
: m9 P. D9 t4 Q4 X- u9 _( j
1 a& ]9 \6 a1 m& ]5 d. t% S$ X! A% X7 F" u" p9 Y; l. t/ ~7 |
这个例子是,trigger在每周一到周五的早上9点到下午5点间,每小时被触发一次。但是两次触发被misfire了,并且在10点15时,才发现这个情况。请注意,他们的失火指令效果与普通trigger是不同的:
% C+ x4 l q% ^: D8 c" u' Q$ s指令 Instruction 意义 Meaning
" D0 V6 _3 i2 R, U3 E: e0 csmart policy - default See: withMisfireHandlingInstructionFireAndProceed
* }1 K8 W5 @0 O- B7 X E) r+ `( K
withMisfireHandlingInstructionIgnoreMisfires
6 v0 e5 f% U1 h( P$ @MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
! [/ p% X# E4 \; c2 M, k8 H. shttps://jira.terracotta.org/jira/browse/QTZ-283
2 I! q$ O4 _6 g* n; y所有被misfire的执行会被立即执行,然后按照正常调度继续执行trigger。
9 l' V2 j. k: v& d
例如:
5 E. O) u7 {& d4 |
9点和10点的执行(misfire的2个)被立即执行,下次执行将在11点被准时执行。
: Y4 F. E0 ~, C" s- M2 g QwithMisfireHandlingInstructionFireAndProceed
7 f3 i. ^- v6 R4 H( q
MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
$ J; s8 u9 G0 {0 u' e立即执行第一次misfire的操作,并且放弃其他misfire的(类似所有misfire的操作被合并执行了)。然后继续按调度执行。无论misfire多少次trigger的执行,都只会立刻执行1次。
* |# L! |8 u. N& p
例如:
( j# G$ p/ p% V! v5 G) ?6 D9 E9点和10点的被合并执行一次(换句话说,10点需要执行的那次,被pass了)。下次执行将在11点被准时执行。
! \' g( u" {2 v* z
withMisfireHandlingInstructionDoNothing
2 l V* t% v, a, P* N8 n' [MISFIRE_INSTRUCTION_DO_NOTHING
: l, w! ?# @2 e! ]1 Y所有被misfire的执行都被忽略掉,调度器会像平时一样等待下次调度。
- b5 S/ p& n' o. K6 V例如:
' a1 T3 X1 t! d2 c3 B; g3 C$ ]9点和10点的被忽略掉,好像什么都没发生一样。下次执行将在11点被执行。
! m0 R- [; Q+ V! i5 K) b ; N" h+ b; w3 i# I- W( d
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,关注下。)
) Q0 I% _8 v8 Q( M$ s% T
& n+ S; i d5 }7 B如你所有,根据实际的设定,不同的trigger会有不同的行为。此外,虽然它提供了smart policy(明智的决策),但是真正使用时,还是要取决于业务需求。
! L2 q7 f+ D4 M9 E9 r% W5 d
从本质上看,主要有三种策略:忽略,立即运行然后继续正常执行,忽略misfire的并等待下次执行。( 原文: ignore, run immediately and continue and discard and wait for next. )
% X8 Z+ q; a0 }/ p8 ?8 S
它们有不同的应用场景:
: c' ^& f8 K; U! M- y7 t, L4 R
当你需要确保每次调度任务都要被执行的时候,即时它意味着多个misfire的trigger会被触发,那么用ignore policies。试想一下,有一个任务,需要每小时,都根据上一小时的订单去生成报表。如果服务被关闭了8个小时,那你可能仍然是尽快得到那些报表的。这种情况下,配置ignore policies,调度器会尽快将那8小时的调度任务运行一遍的。尽管晚了几个小时,但是仍然是被执行了(最终报告到手了。^_^)。
$ P' F6 _+ N' y/ z) @当你需要任务被定期执行,并且当出现misfire的情况后立即运行一次的时候,那么使用now* policies。试想一下,一个任务是每分钟清空文件夹 /tmp。如果调度器在20分钟内繁忙,最后终于可以执行这个任务了,那么你肯定不会希望它执行20次的!一次就足够了,但是要尽快执行。而后,再回到正常的执行间隔--1分钟。
. B: ]! p# U' V8 }. c: A
当你希望任务能在特定时间点运行的时候,使用next* policies不错。比如你需要在每个整点后15分钟抓取股票的价格。它们的变化非常快,然后现在已经整点后20分了,那么不必烦恼。你刚好错过了5分钟,但是现在你已经不在乎(那时候的价格)了。这时,一个时间间隙总好过一个不准确的值。这种情况Quartz只要跳过misfire的操作,等待下次执行就好了。
! w+ N- t* x5 \2 f, o* `
) t2 l# x* Y, X ~+ v; _& k(此文仅为作者观点,我在翻译过程中,其实也有不太明了之处,但是总体来说,还是清晰的,希望大家在以后使用工具时,也更多的关注工具的一切内在功能。)
( @0 a4 c' i ]" S1 _
9 e$ O6 D( i3 z5 I8 c6 g7 ~+ \
0 D& X$ q i% h2 Z7 K/ y8 k3 G再次注明,原文地址:
http://java.dzone.com/articles/quartz-scheduler-misfire
* N" S) r3 ?3 d# Z% M如转,请尊重原作者,贴上链接。
% ^8 X H# f0 t! s$ O: p. f2 n0 }$ D. s" ~ i. o