SimpleTriggers

发表时间:2018-01-11 18:10:40 浏览量( 48 ) 留言数( 0 )

学习目标:

1、深入了解SimpleTrigger的设置

2、了解SimpleTrigger的超时策略


学习过程:

一、SimpleTrigger

1、简单使用

    SimpleTrigger适合对任务需要在指定的时间或者指定的时间后以固定间隔时间重复执行的。比如你想让任务在2015年4月1日 10:00:00执行,并且每一个小时执行一次,并重复的执行。那么使用SimpleTrigger就相对比较简单点。

    重复次数可能是0,正数或者一个常量值SimpleTrigger.REPEAT_INDEFINITELY。重复间隔时间属性可能是0,  正的long型,这个数字以毫秒为单位。注意:如果指定的重复间隔时间是0, 那么会导致触发器按照‘重复数量’定义的次数并发触发(或者接近并发)。  org.quartz.helpers.TriggerUtils 类对处理这样的循环也提供了很多支持。

    endTime(如果这个属性被设置)属性会覆盖重复次数属性,这对创建一个每隔10秒就触发一次直到某个时间结束的触发器非常有用,  这就可以不计算开始时间和结束时间之间的重复数量。也可以指定一个结束时间,然后使用REPEAT_INDEFINITELY作为重复数量。  (甚至可以指定一个大于结束时间之前实际重复次数的整数作为重复次数)。一句话,endTime属性控制权高于重复次数属性。

1、指定时间执行,而且不重复的

Date myStartTime = futureDate(3, IntervalUnit.SECOND);
			
SimpleTrigger trigger = (SimpleTrigger) newTrigger()
					    .withIdentity("trigger1", "group1")
					    .startAt(myStartTime) // some Date
					    .forJob(job) // identify job with name, group strings
					    .build();

2、指定时间执行,并且每10秒执行一次,执行10次。

Date myStartTime = futureDate(3, IntervalUnit.SECOND);
			
			// Trigger the job to run now, and then every 3 seconds
			 SimpleTrigger trigger = (SimpleTrigger)newTrigger()
					    .withIdentity("trigger3", "group1")
					    .startAt(myStartTime)  // if a start time is not given (if this line were omitted), "now" is implied
					    .withSchedule(simpleSchedule()
					        .withIntervalInSeconds(10)
					        .withRepeatCount(10)) // note that 10 repeats will give a total of 11 firings
					    .forJob(job) // identify job with handle to its JobDetail itself                   
					    .build();


3、立即执行一次,并且以后每隔3秒执行一次,知道22:00后停止所有执行。

			 SimpleTrigger trigger = (SimpleTrigger) newTrigger()
					    .withIdentity("trigger7", "group1")
					    .withSchedule(simpleSchedule()
					        .withIntervalInSeconds(3)
					        .repeatForever())
					    .endAt(dateOf(22, 0, 0))
					    .build();

4、下一个整点数执行,并且以后每隔2小时执行一次。

			 SimpleTrigger trigger = newTrigger()
					    .withIdentity("trigger8") // because group is not specified, "trigger8" will be in the default group
					    .startAt(evenHourDate(null)) // get the next even-hour (minutes and seconds zero ("00:00"))
					    .withSchedule(simpleSchedule()
					        .withIntervalInHours(2)
					        .repeatForever())
					    // note that in this example, 'forJob(..)' is not called
					    //  - which is valid if the trigger is passed to the scheduler along with the job  
					    .build();

5、可以结合我们上一节课学些的Calendar配置使用的

 SimpleTrigger trigger = newTrigger()
					    .withIdentity("trigger8") // because group is not specified, "trigger8" will be in the default group
					    .startAt(myStartTime) // get the next even-hour (minutes and seconds zero ("00:00"))
					    .withSchedule(simpleSchedule()
					        .withIntervalInSeconds(4)
					        .repeatForever()).modifiedByCalendar("nodays")
					    // note that in this example, 'forJob(..)' is not called
					    //  - which is valid if the trigger is passed to the scheduler along with the job  
					    .build();


2、超时策略

配置文件的配置。

org.quartz.jobStore.misfireThreshold = 5000

   要弄清楚触发器超时临界值的意义,那么就要先弄清楚什么是触发器超时?打个比方:比如调度引擎中有5个线程,然后在某天的下午2点 有6个任务需要执行,那么由于调度引擎中只有5个线程,所以在2点的时候会有5个任务会按照之前设定的时间正常执行,有1个任务因为没有线程资源而被延迟执行,这个就叫触发器超时。

理解了上面的内容再来看misfireThreshold值的意义,misfireThreshold是用来设置调度引擎对触发器超时的忍耐时间,简单来说 假设misfireThreshold=6000(单位毫秒)。

   那么它的意思说当一个触发器超时时间如果大于misfireThreshold的值 就认为这个触发器真正的超时(也叫Misfires)。如果一个触发器超时时间 小于misfireThreshold的值, 那么调度引擎则不认为触发器超时。也就是说调度引擎可以忍受这个超时的时间。


    第一种情况:任务出现延时,延时的时间<misfireThreshold。比如一个任务正常应该在2点运行,但是调度系统忙碌2点5秒才得空运行这个任务,这样这个任务就被耽误了5秒钟。假设这个任务的触发器定义的是 2点执行 时间间隔为1秒 执行10次。如果正常情况 任务应该在 2点00秒 ,2点01秒,2点03秒....2点10秒触发。但这个任务在2点05秒的时候引擎在后空去执行它,这样的话就比我们预期的时间慢了5秒。那么调度引擎是如何执行这个任务的呢?不是是应该在在2点05秒开始执行 然后一直到2点15秒呢?经过测试我发现并不是这样的,而是调度引擎直接把慢了的那5次立即运行,然后再每隔1秒运行5次。


    第二种情况:任务触发器超时,延迟的时间>=misfireThreshold,那么调度引擎该如何处理这个任务呢?答案是这样的:在定义一个任务的触发器的时候,我们可以设置它超时的处理策略,调度引擎会根据我们设置的策略来处理这个任务。我们在定义一个任务的触发器时 最常用的就是俩种触发器:1、SimpleTrigger 2、CronTrigger。


    我们一般就使用SimpleTrigger 默认的策略是 Trigger.MISFIRE_INSTRUCTION_SMART_POLICY,这种智能的策略就可以了。在文档的 SimpleTrigger.updateAfterMisfire() 方法里面有这种策略的详细介绍:


智能策略的方案是:

1、如果触发器的重复执行数(Repeat Count)等于0,那么会按这个(MISFIRE_INSTRUCTION_FIRE_NOW)策略执行。

2、如果触发器的重复执行次数是 SimpleTrigger.REPEAT_INDEFINITELY (常量值为-1,意思是重复无限次) ,那么会按照MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT策略执行。

3、如果触发器的重复执行次数大于0,那么按照 MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT执行。


有六种策略的常量配置

MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY

MISFIRE_INSTRUCTION_FIRE_NOW

MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT

MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT

MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT

MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT


1、MISFIRE_INSTRUCTION_FIRE_NOW

指示调度引擎在MisFire的情况下,将任务(JOB)马上执行一次。需要注意的是 这个指令通常被用做只执行一次的Triggers,也就是没有重复的情况(non-repeating),如果这个Triggers的被安排的执行次数大于0。那么这个执行与 (4)MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT 相同


2、MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT

指示调度引擎重新调度该任务,repeat count保持不变,并且服从trigger定义时的endTime,如果现在的时间,如果当前时间已经晚于 end-time,那么这个触发器将不会在被激发。

注意:这个状态会导致触发器忘记最初设置的 start-time 和 repeat-count,为什么这个说呢,看源代码片段:updateAfterMisfire方法中

getTimesTriggered的是获取这个触发器已经被触发了多少次,那么用原来的次数 减掉 已经触发的次数就是还要触发多少次

接下来就是判断一下触发器是否到了结束时间,如果到了的话,触发器就不会在被触发。

然后就是重新设置触发器的开始实现是 “现在” 并且立即运行。


3、MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT

这个策略跟上面的2策略一样,唯一的区别就是设置触发器的时间 不是“现在” 而是下一个 scheduled time。解释起来比较费劲,举个例子就能说清楚了。

比如一个触发器设置的时间是 10:00 执行 时间间隔10秒 重复10次。那么当10:07秒的时候调度引擎可以执行这个触发器的任务。那么如果是策略(2),那么任务会立即运行。

那么触发器的触发时间就变成了 10:07  10:17 10:27 10:37 .....

那么如果是策略(3),那么触发器会被安排在下一个scheduled time。 也就是10:20触发。 然后10:30 10:40 10:50。


4、MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT

   这个策略跟上面的策略(2)比较类似,指示调度引擎重新调度该任务,repeat count 是剩余应该执行的次数,也就是说本来这个任务应该执行10次,但是已经错过了3次,那么这个任务就还会执行7次。


5、MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT

这个策略与上面的策略3比较类似,区别就是repeat count 是剩余应该执行的次数而不是全部的执行次数。比如一个任务应该在2:00执行,repeat count=5,时间间隔5秒, 但是在2:07才获得执行的机会,那任务不会立即执行,而是按照机会在2点10秒执行。


6、MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY

这个策略是忽略所有的超时状态,和最上面讲到的 (第二种情况) 一致。举个例子,一个SimpleTrigger  每个15秒钟触发, 但是超时了5分钟才获得执行的机会,那么这个触发器会被快速连续调用20次, 追上前面落下的执行次数。


当然我们也可以自己指定使用的策略是什么:

			SimpleTrigger  trigger = newTrigger()
					    .withIdentity("trigger7", "group1")
					    .withSchedule(simpleSchedule()
					        .withIntervalInMinutes(5)
					        .repeatForever()
					        .withMisfireHandlingInstructionNextWithExistingCount())
					    .build();