quartz定时任务不执行(任务统筹策略)

由于某种原因,例如应用停掉,导致定时任务错过了本该执行的时间点,这就是定时任务过期。对于过期的定时任务,我们需要基于某种策略对其进行处理。过期策略在Trigger接口中定义了两种过期策略,publicstaticfinalintMISFIRE_INSTRUCTION_SMART_POLICY=0;publicstaticfinalintMISF…

大家好,又见面了,我是你们的朋友全栈君。

由于某种原因,例如应用停掉,导致定时任务错过了本该执行的时间点,这就是定时任务过期。对于过期的定时任务,我们需要基于某种策略对其进行处理。

过期策略

在Trigger接口中定义了两种过期策略,

    public static final int MISFIRE_INSTRUCTION_SMART_POLICY = 0;
    
    public static final int MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1;

MISFIRE_INSTRUCTION_SMART_POLICY 表明过期的定时任务将使用智能策略,如何处理将依赖于具体的Trigger实现类。等会我们会专门分析最常用的CronTrigger的智能过期策略的实现。
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY 表明对于过期的定时任务将不执行任何过期策略。

设定过期策略

以CronTrigger为例,我们在添加定时任务的时候可以通过CronSchedulerBuilder设定过期策略。

 JobDetail jobDetail = JobBuilder.newJob(PrintJob.class)
                .storeDurably(true)
                .withIdentity(id)
                .withDescription(desc)
                .setJobData(jobDataMap).build();

CronScheduleBuilder schBuilder = CronScheduleBuilder.cronSchedule(cron)
.withMisfireHandlingInstructionFireAndProceed();

Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(id)
                .withDescription(desc)
                .forJob(jobDetail)
                .withSchedule(schBuilder).build();

如果不指定默认就是MISFIRE_INSTRUCTION_SMART_POLICY ,即采用智能策略模式。

CronTrigger过期策略

CronTrigger的智能过期策略有两种

public static final int MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1;
public static final int MISFIRE_INSTRUCTION_DO_NOTHING = 2;

看字面意思很好理解,第一种是立即触发一次,第二种是忽略掉不管。定时任务过期后,需要对triiger进行处理,具体的处理是在具体的Trigger实现类中实现的,例如CronTriggerImpl

@Override
    public void updateAfterMisfire(org.quartz.Calendar cal) { 
   
        int instr = getMisfireInstruction();

        if(instr == Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY)
            return;

        if (instr == MISFIRE_INSTRUCTION_SMART_POLICY) { 
   
            instr = MISFIRE_INSTRUCTION_FIRE_ONCE_NOW;
        }

        if (instr == MISFIRE_INSTRUCTION_DO_NOTHING) { 
   
            Date newFireTime = getFireTimeAfter(new Date());
            while (newFireTime != null && cal != null
                    && !cal.isTimeIncluded(newFireTime.getTime())) { 
   
                newFireTime = getFireTimeAfter(newFireTime);
            }
            setNextFireTime(newFireTime);
        } else if (instr == MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) { 
   
            setNextFireTime(new Date());
        }
    }

从源码中可以看到,CronTrigger的默认智能策略就是立即触发一次(MISFIRE_INSTRUCTION_FIRE_ONCE_NOW),即更新下次触发时间为当前时间。

过期定时任务检测

前半部分我们讲了定时任务的过期策略,并以CronTrigger为例,说明了其智能过期策略是如何实现的。后半部分,我们将视角从Trigger提升到Scheduler,看看Quartz是如何检测出过期定时任务的。

在JobStoreSupport中有一个叫MisfireHandler的线程,它负责定期检测出那些过期的定时任务。我们来看看它是如何做的。

首先,我们要明确一个过期的标准。一个比较直观的想法就是,如果一个Trigger的下次触发时间在当前时间之前,那么这个定时任务肯定是过期了。但是我们为了给人家一个机会,可以通过减去一个值,稍稍把这个截止时间调前一点。这个值可以通过quartz.properties配置,默认是60000,即60秒。

org.quartz.jobStore.misfireThreshold: 10000

当然Trigger必须是WAITING状态下才行,非WAITING状态的Trigger表明定时任务正在处理,已经完成或者出错了。而且过期策略不是MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY 。

有了这三个过期指标,过期的定时任务就好筛选了。我们去QRTZ_TRIGGERS表里面,把符合这三个条件的Trigger都筛选出来。

过期定时任务恢复

以MISFIRE_INSTRUCTION_FIRE_ONCE_NOW过期策略为例,拿到过期的Trigger后,根据过期策略,调用updateAfterMisfire()对其进行更新,包括设置下次触发时间,更新状态为WAITING。

处理完trigger后,MisfireHandler会立即向QuartzSchedulerThread发送信号,告诉有紧急任务达到。

if (recoverMisfiredJobsResult.getProcessedMisfiredTriggerCount() > 0) { 
   
          
  signalSchedulingChangeImmediately(recoverMisfiredJobsResult.getEarliestNewTime());
}

QuartzSchedulerThread接收到信号后,如果才刚刚开始扫描触发器则必定能扫描到这个触发器,所以不用做任何额外处理。如果已经获取过触发器了,则释放掉已经获取的触发器,重新开始扫描。

if(releaseIfScheduleChangedSignificantly(triggers, triggerTime)) { 
   
   break;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/128399.html原文链接:https://javaforall.net

(1)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • PHP递归算法_php递归函数详解

    PHP递归算法_php递归函数详解先设置数据在本地数据库,设置前要先了解pid字段的关系。如果做成菜单还需添加一个路由字段,自行定义。第一种方式先将数据提取出转换成数组。重点是Yarray方法里的递归方式。接下来进行解析方式。重点:一定要在进行递归之前声明一个静态数组,不然会导致数组覆盖。剩下的就是注释的内容也就是判断父节点与节点来判断等级。这步指来回方法调用本身进行处理递归。最后数据会变成其中关系为pid数值存在与id下的下级关系,level为处于第几级;我们来输出一下看看结.

    2022年8月11日
    4
  • kafka实战教程(python操作kafka),kafka配置文件详解

    kafka实战教程(python操作kafka),kafka配置文件详解什么是kafka安装参考:https://www.cnblogs.com/hei12138/p/7805475.html

    2022年4月30日
    41
  • redflag linux7.0 grub引导终极原创

    redflag linux7.0 grub引导终极原创很多同志在安装redflag时,安装引导时选了将引导安装在根分区而不是MBR分区,所以开机时还是只能进入XP系统而不能进入Linux系统其实要解决这个问题,引导进入redflag很简单,只要在xp下的C盘中找到menu.ls这个文件,用记事本找开,在其中添加title红旗Linux桌面7root(hd0,8)kernel/boot/vmlinuz-2.6….

    2022年8月20日
    4
  • IDEA激活成功教程后一直提示JetbrainsAgent 相关的弹框问题

    IDEA激活成功教程后一直提示JetbrainsAgent 相关的弹框问题激活成功教程后打开IDEA就弹框,关闭之后会自动打开浏览器,隔一会也会弹出来 也是一样的问题一开始是说把txt 和 jar 文件放一个路径下之类的方法,几经波折,发现没任何用处~最后各种搜索排查,在设置下更改配置就不弹啦~settings设置下搜索agent 取消”Instrumenting agent(requires debugger restart)”在 Reload classes after compilation:选择第一个 Always…

    2022年8月19日
    4
  • 语义分割总结_细粒度语义分割

    语义分割总结_细粒度语义分割图像分割算法总结1.评价指标:普通指标:PixelAccuracy(PA,像素精度):标记正确的像素点占所有像素点的比例。混淆矩阵中=\(\frac{{\rm{对角线}}}{总和}\)Mea

    2022年8月5日
    3
  • Spring+Struts+Hibernate 简介(转)

    Spring+Struts+Hibernate 简介(转)

    2021年9月10日
    62

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号