quartz2.3.0制定错过执行任务的misfire策略

Posted zhuwenjoyce

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了quartz2.3.0制定错过执行任务的misfire策略相关的知识,希望对你有一定的参考价值。

感谢兄台: 《quartz-misfire 错失、补偿执行

misfire定义

 misfire:被错过的执行任务策略

misfire重现——CronTrigger

job任务类:

package org.quartz.examples.example5;

import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.PersistJobDataAfterExecution;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * <pre>
 * 任务job。
 * 因为@DisallowConcurrentExecution注解,所以这个job不可以被多个定时器或触发器同时执行,否则会触发定时器的misfire,就需要我们定义好定时器的misfire策略。
 * 如果不定义misfire,会出现
 * </pre>
 */
@PersistJobDataAfterExecution  //持久化JobDataMap里的数据,使下一个定时任务还能获取到这些值
@DisallowConcurrentExecution  //禁止并发多任务执行,所以永远只有一个任务在执行中
public class StatefulDumbJob implements Job 

    //任务执行计数器
    public static final String NUM_EXECUTIONS = "NumExecutions";
    public static final String EXECUTION_DELAY = "ExecutionDelay";
    public static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

    //必须要有public修饰的无参构造函数
    public StatefulDumbJob() 
    

    //定时器执行方法
    public void execute(JobExecutionContext context) throws JobExecutionException 
        System.out.println("---" + context.getJobDetail().getKey() + " executing.   [" + SDF.format(new Date()) + "]");
        //获得带状态集合
        JobDataMap map = context.getJobDetail().getJobDataMap();

        int executeCount = 0;
        if (map.containsKey(NUM_EXECUTIONS)) 
            executeCount = map.getInt(NUM_EXECUTIONS);
        

        executeCount++;

        map.put(NUM_EXECUTIONS, executeCount);

        System.out.println("  -" + context.getJobDetail().getKey() + " complete (" + executeCount + ").[" + SDF.format(new Date())+ "]");

    

定时器类:

package org.quartz.examples.example5;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.DateBuilder.nextGivenSecondDate;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

import java.util.Date;

import org.quartz.CronExpression;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdScheduler;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <pre>
此类演示了如何定义定时器的misfire策略。misfire:被错过的执行任务策略
 * </pre>
 */
public class MisfireExample_CronScheduleBuilder 
    static final Logger LOG = LoggerFactory.getLogger(MisfireExample_CronScheduleBuilder.class);

    public static void main(String[] args) throws Exception 
        // 初始化一个调度工厂,并实例化一个调度类
        SchedulerFactory sf = new StdSchedulerFactory();
//                        Scheduler sched = sf.getScheduler();
        StdScheduler sched = (StdScheduler) sf.getScheduler();

        // 第一个参数:null就是默认当前时间,也可以指定时间
        // 第二个参数:把一分钟按10进行划分,也就是60/10等份。
        // 举例:当前时间是10:26:04,那么startTime就是10:30:00。当前时间是10:38:31,那么startTime就是10:40:00。
        Date startTime = nextGivenSecondDate(null, 10);
        JobDetail job = newJob(StatefulDumbJob.class).withIdentity("job1", "group1")
//                                .usingJobData(StatefulDumbJob.EXECUTION_DELAY, 30000L)
                .build();
        String cron = "0/2 * * * * ?"; // 每2秒执行一次

        CronScheduleBuilder cronScheduleBuilder = cronSchedule(new CronExpression(cron));

        // ========================================================================
        // ======================== misfire定义,开始 =======================
        // ========================================================================

        /*
         设置misfire策略:CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING = 2 
         ——不触发立即执行
         ——等待下次Cron触发频率到达时刻开始按照Cron频率依次执行
         */
        cronScheduleBuilder.withMisfireHandlingInstructionDoNothing();

        /*
         设置misfire策略:Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1
         ——以错过的第一个频率时间立刻开始执行 ——重做错过的所有频率周期 ——当下一次触发频率发生时间大于当前时间以后,按照Interval的依次执行剩下的频率
         ——共执行RepeatCount+1次
         */
//        cronScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires(); 

        /*
         * 设置misfire策略:CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1
         * 以当前时间为触发频率立刻触发一次执行,然后按照Cron频率依次执行
         */
//        cronScheduleBuilder.withMisfireHandlingInstructionFireAndProceed(); 

        // ========================================================================
        // ======================== misfire定义,结束 =======================
        // ========================================================================

        CronTrigger trigger = newTrigger().withIdentity("trigger1", "group1").startAt(startTime)
                .withSchedule(cronScheduleBuilder).build();

        // CronTrigger默认misfire策略是: org.quartz.Trigger.MISFIRE_INSTRUCTION_SMART_POLICY = 0
        int misfireInstruction = trigger.getMisfireInstruction();
        LOG.info("当前misfire策略:" + misfireInstruction);

        Date ft = sched.scheduleJob(job, trigger);
        LOG.info(job.getKey().toString());

        sched.start();
        LOG.info("调度器启动,主线程睡眠15秒!!!!调度器内任务线程继续执行。");
        Thread.sleep(15L * 1000L);

//        // 暂停触发器
//        sched.pauseTrigger(trigger.getKey());
//        // 继续触发器
//        sched.resumeTrigger(trigger.getKey());

        // 暂停执行任务
        sched.pauseJob(job.getKey());
        LOG.info("调度器暂停执行定时器,主线程睡眠11秒!!!!会错过执行job1的N次定时任务。模拟当定时器的执行线程由于抢不到CPU时间或其他事件错过执行的情况。");
        Thread.sleep(11L * 1000L);
        // 继续执行任务
        sched.resumeJob(job.getKey()); //当定时器得到继续执行的命令时,被错过执行的任务次数,就会按照misfire的定义去执行

        LOG.info("调度器继续执行定时器,主线程睡眠15秒!!!!调度器内任务线程继续执行。");
        Thread.sleep(15L * 1000L);
        
        LOG.info("调度器终止执行!!!!");
        sched.shutdown(true);
    

 

以上是关于quartz2.3.0制定错过执行任务的misfire策略的主要内容,如果未能解决你的问题,请参考以下文章

quartz2.3.0使用日历排除不应该执行任务的时间段

quartz2.3.0job任务监听器,监听任务执行前后取消手动处理方法

quartz2.3.0(十五)执行暂停继续执行清除,花式操作数据库中持久化的job任务

quartz2.3.0xml配置方式定义quartz定时任务

quartz 任务调度问题,每次都执行两次 相隔只有几微秒

SpringBoot开发案例之整合Quartz任务管理系统