Quartz框架(一)—Quartz的基本配置
Quartz框架(二)—jobstore数据库表字段详解
Quartz框架(三)—任务的并行/串行执行
Quartz框架(四)—misfire处理机制
Quartz框架(五)— 有状态的job和无状态job
Quartz框架(六)— Trigger状态转换
Quartz框架(七)— Quartz集群原理
Quartz框架(八)— Quartz实现异步通知
Quartz框架(九)— 动态操作Quartz定时任务
Quartz框架(十)监听
什么叫做misfire
在Quartz中,当一个持久化的触发器因为:
1. 调度器被关闭;
2. 线程池没有可用线程;
3. 项目重启;
4. 任务的串行执行;
而错过激活时间,就会发生激活失败(misfire)。
此时我们需要明确两个问题(1)如何判定激活失败;(2)如何处理激活失败;
1. 如何判定激活失败
在Quartz框架(一)—Quartz的基本配置中,quartz.properties配置文件中含有一个属性是misfireThreshold(单位毫秒),用来指定调度引擎设置触发器超时的“临界值”。也就是说Quartz对于任务的超时是有容忍度的。只有超过这个容忍度才会判定位misfire。
quartz.properties的配置文件
#设置容忍度为12s
org.quartz.jobStore.misfireThreshold = 12000
Corn=[*/2 * * * * ?] 即每两秒循环一次
jobDetail每次执行需要7s
@Component
@DisallowConcurrentExecution
public class TestJob2 extends CustomQuartzJobBean{
private Logger logger = LoggerFactory.getLogger(TestJob2.class);
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
logger.info("【数据库配置定时】-【开始】");
try {
Thread.sleep(7000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("【数据库配置定时】-【结束】");
}
}
任务编号 | 预定运行时刻 | 实际运行时刻 | 延迟量(秒) |
---|---|---|---|
1 | 17:54:00 | 17:54:00 | 0 |
2 | 17:54:02 | 17:54:07 | 5 |
3 | 17:54:04 | 17:54:14 | 10 |
4 | 17:54:06 | 17:54:21 | misfire |
从表中可以看到,每一次任务的延迟都是5s作用,该延迟量不断累积,并且与misfireThreshold比较,直到在17:54:21时发生了misfire,那么17:54:21第4次任务会不会执行呢,答案是不一定的,取决于配置。
2. 激活失败的处理
激活失败指令(Misfire Instruction[因死抓可神 指令]
)是触发器的一个重要配置。所有类型的触发器都有一个默认的指令:
Trigger.MISFIRE_INSTRUCTION_SMART_POLICY
但是这个“机智策略(policy [跑了谁]
)”对于不同类型的触发器其具体行为是不同的。
misfire Instruction在qutz_triggers表中的字段。
代码中设置misfire策略的方式。
2.1 quartz中CornTrigger使用的策略
//所有的misfile任务马上执行
public static final int MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1;
//在Trigger中默认选择MISFIRE_INSTRUCTION_FIRE_ONCE_NOW 策略
public static final int MISFIRE_INSTRUCTION_SMART_POLICY = 0;
// CornTrigger默认策略,合并部分misfire,正常执行下一个周期的任务。
public static final int MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1;
//所有的misFire都不管,执行下一个周期的任务。
public static final int MISFIRE_INSTRUCTION_DO_NOTHING = 2;
- 可以通过setMisfireInstruction方法设置misfire策略。
CronTriggerFactoryBean triggerFactoryBean = new CronTriggerFactoryBean();
triggerFactoryBean.setName("corn_" + clazzName);
triggerFactoryBean.setJobDetail(jobFactory.getObject());
triggerFactoryBean.setCronExpression(quartzCorn);
triggerFactoryBean.setGroup(QUARTZ_TRIGGER_GROUP);
//设置misfire策略
triggerFactoryBean.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY);
triggerFactoryBean.afterPropertiesSet();
- 也可以通过CronScheduleBuilder设置misfire策略。
CronScheduleBuilder csb = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");
//MISFIRE_INSTRUCTION_DO_NOTHING
csb.withMisfireHandlingInstructionDoNothing();
//MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
csb.withMisfireHandlingInstructionFireAndProceed();//(默认)
//MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
csb.withMisfireHandlingInstructionIgnoreMisfires();
策略的具体含义
前提:在每个星期周一下午5点到7点,每隔一个小时执行一次,理论上共执行3次。
1. 情景一:
//所有misfire的任务会马上执行
public static final int MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1;
若是5点misfire,6:15系统恢复之后,5,6点的misfire会马上执行。
2. 情景二:
//不做任何事情
public static final int MISFIRE_INSTRUCTION_DO_NOTHING = 2;
若是5点misfire,6:15系统恢复之后,只会执行7点的misfire。如果下次执行时间超过了end time,实际上就没有执行机会了。
3. 情景三:(cronTrigger的默认策略)
// CornTrigger默认策略,合并部分misfire,正常执行下一个周期的任务。
public static final int MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1;
若是5点misfire,6:15系统恢复之后,立刻执行一次(只会一次)misfire。
2.2 quartz中SImpleTrigger使用的策略
-
若是使用
MISFIRE_INSTRUCTION_SMART_POLICY
—机智的策略- 如果Repeat=0; 【重复0次】
instruction selected = MISFIRE_INSTRUCTION_FIRE_NOW;【立刻执行,对于不会重复执行的任务,只是默认的处理策略。】 - 如果Repeat Count=REPEAT_INDEFINITELY;【无限重复】
instruction selected = MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT;【在下一个激活点执行,且错过的执行机会作废。】 - 如果Repeat Count>0;【有限重复】
instruction selected = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT;【立即执行,并执行指定的次数。】
- 如果Repeat=0; 【重复0次】
3. misfire的执行流程
- 若配置(默认为true,可配置)成获取锁前先检查是否有需要recovery的trigger,先获取misfireCount;
- 获取TRIGGER_ACCESS锁;
- misfired的判断依据:status=waiting,current_time-next_fire_time>misfireThreshold(可配置,默认1分钟)【即实际触发时间-预计触发时间大于容忍度时间】,获取misfired的trigger,默认一个事务中只能最大有20个misfired trigger(可配置)。
- updateAfterMisfired:获取misfired的策略(默认是MISFIRE_INSTRUCTION_SMART_POLICY该策略在CronTrigger中为MISFIRE_INSTRUCTION_FIRE_ONCE_NOW),根据策略更新nexFireTime。
- 将nextFireTime等更新到trigger表;
- commit connection,释放锁。