Quartz 之 Job Misfires

Posted 秋风小凉鱼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Quartz 之 Job Misfires相关的知识,希望对你有一定的参考价值。

项目地址:  

         https://github.com/yuleiqq/quartz_example/tree/master/quartz_study

此示例旨在演示与触发错误触发相关的概念。

程序将执行以下操作:

  • 启动Quartz 调度器
  • 计划两个作业,每个作业将无限期地每三秒钟执行一次
  • 运行作业需要10秒(防止执行触发器每三秒触发一次)
  • 每个作业都有不同的失败指令

  • 程序将等待10分钟,以便两个作业有足够的时间运行

  • 停止调度器

代码有如下类组成:

类名描述
MisfireExample主程序
StatefulDumbJob运行一个简单的job类,它的execute方法需要10秒钟

 

StatefulDumbJob

StatefulDumbJob是一个简单的作业,它打印它的执行时间,然后在完成之前等待一段时间。

等待时间量由作业参数EXECUTION_DELAY定义。如果没有传入此作业参数,则该作业将默认为5秒的等待时间。该作业还保留自己的计数,即使用其JobDataMap中名为num_的值执行了多少次。因为该类具有PersistJobDataAfterExecution注释,所以在每次执行之间保留执行计数。

package com.example06;

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

import java.util.Date;

/**
 * @author :  yulei
 * @data :  2020/5/21 21:18
 * @Version :  1.0
 **/

public class StatefulDumbJob  implements Job 

    //执行次数累计
    public static final String NUM_EXECUTIONS = "NumExecutions";
    //延迟执行时间
    public static final String EXECUTION_DELAY = "ExecutionDelay";

    public StatefulDumbJob() 
    

    public void execute(JobExecutionContext context) throws JobExecutionException 
        System.err.println("---" + context.getJobDetail().getKey()
                + " executing.[" + 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);


        long delay = 5000l;
        if (map.containsKey(EXECUTION_DELAY)) 
            delay = map.getLong(EXECUTION_DELAY);
        
        try 
            Thread.sleep(delay);
         catch (Exception ignore) 
        

        System.err.println("  -" + context.getJobDetail().getKey()
                + " complete (" + executeCount + ").");


    

 

MisfireExample

程序首先获取调度程序的一个实例。这是通过创建一个StdSchedulerFactory来完成的,然后使用它来创建一个调度器。这将创建一个简单的基于RAM的调度器,因为没有特定的 quartz.properties配置文件 告诉它执行其他操作。

package com.example06;

import static org.quartz.DateBuilder.nextGivenSecondDate;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;

/**
 * @author :  yulei
 * @data :  2020/5/21 21:30
 * @Version :  1.0
 **/

public class MisfireExample 

    public void run() throws Exception 
        Logger log = LoggerFactory.getLogger(MisfireExample.class);
        log.info("------- Initializing -------------------");
        SchedulerFactory sf = new StdSchedulerFactory();
        Scheduler sched = sf.getScheduler();
        log.info("------- Initialization Complete -----------");

        Date startTime = nextGivenSecondDate(null, 15);

        //statefulJob1 3秒钟执行一次 (但是会延迟10秒)
        JobDetail job = newJob(StatefulDumbJob.class).withIdentity("statefulJob1", "group1")
                .usingJobData(StatefulDumbJob.EXECUTION_DELAY, 10000L).build();

        SimpleTrigger trigger = newTrigger().withIdentity("trigger1", "group1").startAt(startTime)
                .withSchedule(simpleSchedule().withIntervalInSeconds(3).repeatForever()).build();

        Date ft = sched.scheduleJob(job, trigger);
        log.info(job.getKey() + " will run at: " + ft + " and repeat: " + trigger.getRepeatCount() + " times, every "
                + trigger.getRepeatInterval() / 1000 + " seconds");


        // statefulJob2每三秒钟运行一次
        //(但是它会延迟10秒—因此在几次迭代之后故意失火)
        job = newJob(StatefulDumbJob.class).withIdentity("statefulJob2", "group1")
                .usingJobData(StatefulDumbJob.EXECUTION_DELAY, 10000L).build();

        trigger = newTrigger()
                .withIdentity("trigger2", "group1")
                .startAt(startTime)
                .withSchedule(simpleSchedule().withIntervalInSeconds(3).repeatForever()
                        .withMisfireHandlingInstructionNowWithExistingCount()) // set misfire instructions
                .build();

        ft = sched.scheduleJob(job, trigger);
        log.info(job.getKey() + " will run at: " + ft + " and repeat: " + trigger.getRepeatCount() + " times, every "
                + trigger.getRepeatInterval() / 1000 + " seconds");

        log.info("------- Starting Scheduler ----------------");
        sched.start();
        log.info("------- Started Complete -----------------");
        try 
            // sleep for ten minutes for triggers to file....
            Thread.sleep(600L * 1000L);
         catch (Exception e) 
            //
        
        log.info("------- Shutting Down ---------------------");

        sched.shutdown(true);

        log.info("------- Shutdown Complete -----------------");

        SchedulerMetaData metaData = sched.getMetaData();
        log.info("Executed " + metaData.getNumberOfJobsExecuted() + " jobs.");

    

    public static void main(String[] args) throws Exception 
        MisfireExample example = new MisfireExample();
        example.run();

    


withMisfireHandlingInstructionNowWithExistingCount
——以当前时间为触发频率立即触发执行
——执行至FinalTIme的剩余周期次数
——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值

 

执行后,运行结果如下:

--group1.statefulJob1 executing.[Thu May 21 22:07:15 CST 2020]
---group1.statefulJob2 executing.[Thu May 21 22:07:15 CST 2020]
  -group1.statefulJob1 complete (1).
  -group1.statefulJob2 complete (1).
---group1.statefulJob2 executing.[Thu May 21 22:07:25 CST 2020]
---group1.statefulJob1 executing.[Thu May 21 22:07:27 CST 2020]
  -group1.statefulJob2 complete (2).
---group1.statefulJob2 executing.[Thu May 21 22:07:35 CST 2020]
  -group1.statefulJob1 complete (2).
---group1.statefulJob1 executing.[Thu May 21 22:07:39 CST 2020]
  -group1.statefulJob2 complete (3).
---group1.statefulJob2 executing.[Thu May 21 22:07:45 CST 2020]
  -group1.statefulJob1 complete (3).
---group1.statefulJob1 executing.[Thu May 21 22:07:51 CST 2020]
  -group1.statefulJob2 complete (4).
---group1.statefulJob2 executing.[Thu May 21 22:07:55 CST 2020]
  -group1.statefulJob1 complete (4).
---group1.statefulJob1 executing.[Thu May 21 22:08:03 CST 2020]
  -group1.statefulJob2 complete (5).
---group1.statefulJob2 executing.[Thu May 21 22:08:05 CST 2020]

可以看到 job2 在延迟10秒之后是立即执行的.   而 job1 还是按照 正常的3秒一次执行,错过上次频率,会在下次触发频率开始执行.

 

 

 

以上是关于Quartz 之 Job Misfires的主要内容,如果未能解决你的问题,请参考以下文章

Quartz 之 处理Job 异常

Quartz之Job与JobDetail浅析

SpringBoot之Quartz实战

Quartz之入门实例

Quartz学习 之 Jobs 和 Triggers

Quartz教程三:Job与JobDetail介绍