quartz2.3.0(五)制定錯過執行任務的misfire策略

感謝兄臺: 《quartz-misfire 錯失、補償執行html

misfire定義java

 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())+ "]");

    }

}

定時器類:ui

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);
    }

}

 misfire重現——SimpleTriggerspa

CronTrigger的misfire策略經本人親自測試,註釋所有可靠,SimpleTrigger所有來自如下兄臺文章註釋,實際結果請各位親自實驗。線程

感謝兄臺: 《quartz-misfire 錯失、補償執行code

SimpleTrigger默認misfire策略也是: org.quartz.Trigger.MISFIRE_INSTRUCTION_SMART_POLICY = 0orm

//定義觸發器,2秒執行一次,循環5次,總共執行6次
        SimpleScheduleBuilder simpleScheduleBuilder = simpleSchedule().withIntervalInSeconds(2).withRepeatCount(5);
//                .repeatForever(); //無限循環
        
        /*
           設置misfire策略爲:SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT = 5
             ——不觸發當即執行
            ——等待下次觸發頻率週期時刻,執行至FinalTime的剩餘週期次數
            ——以startTime爲基準計算週期頻率,並獲得FinalTime
            ——即便中間出現pause,resume之後保持FinalTime時間不變
         */
        simpleScheduleBuilder.withMisfireHandlingInstructionNextWithExistingCount();
        
        /*
           設置misfire策略爲:SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT = 4
             ——不觸發當即執行
            ——等待下次觸發頻率週期時刻,執行至FinalTime的剩餘週期次數
            ——以startTime爲基準計算週期頻率,並獲得FinalTime
            ——即便中間出現pause,resume之後保持FinalTime時間不變
         */
        simpleScheduleBuilder.withMisfireHandlingInstructionNextWithRemainingCount();
        
        /*
           設置misfire策略爲:SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT = 3
             ——以當前時間爲觸發頻率當即觸發執行
            ——執行至FinalTIme的剩餘週期次數
            ——以調度或恢復調度的時刻爲基準的週期頻率,FinalTime根據剩餘次數和當前時間計算獲得
            ——調整後的FinalTime會略大於根據starttime計算的到的FinalTime值
         */
        simpleScheduleBuilder.withMisfireHandlingInstructionNowWithRemainingCount();
        
        /*
           設置misfire策略爲:SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT = 2
            ——以當前時間爲觸發頻率當即觸發執行
            ——執行至FinalTIme的剩餘週期次數
            ——以調度或恢復調度的時刻爲基準的週期頻率,FinalTime根據剩餘次數和當前時間計算獲得
            ——調整後的FinalTime會略大於根據starttime計算的到的FinalTime值
         */
        simpleScheduleBuilder.withMisfireHandlingInstructionNowWithExistingCount();
        
        /*
           設置misfire策略爲:SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW = 1
             ——以當前時間爲觸發頻率當即觸發執行
            ——執行至FinalTIme的剩餘週期次數
            ——以調度或恢復調度的時刻爲基準的週期頻率,FinalTime根據剩餘次數和當前時間計算獲得
            ——調整後的FinalTime會略大於根據starttime計算的到的FinalTime值
         */
        simpleScheduleBuilder.withMisfireHandlingInstructionFireNow();
        
        /*
           設置misfire策略爲:Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1
             ——以錯過的第一個頻率時間馬上開始執行
            ——重作錯過的全部頻率週期
            ——當下一次觸發頻率發生時間大於當前時間之後,按照Interval的依次執行剩下的頻率
            ——共執行RepeatCount+1次
         */
        simpleScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires();
相關文章
相關標籤/搜索