欢迎您的访问
专注架构,Java,数据结构算法,Python技术分享

Quartz源码(四):Quartz调度器的Misfire处理规则

一、SimpleTrigger的misfire机制 默认的 Trigger.MISFIRE_INSTRUCTION_SMART_POLICY !!!

trig.updateAfterMisfire(cal);
getMisfireInstruction() —-> misfireInstruction == 0
——以当前时间为触发频率立即触发执行

    SimpleScheduleBuilder ssb = SimpleScheduleBuilder.simpleSchedule();

    ssb.withMisfireHandlingInstructionFireNow();//1
    ssb.withMisfireHandlingInstructionIgnoreMisfires();//2
    ssb.withMisfireHandlingInstructionNextWithExistingCount();//3
    ssb.withMisfireHandlingInstructionNextWithRemainingCount();//4
    ssb.withMisfireHandlingInstructionNowWithExistingCount();//5
    ssb.withMisfireHandlingInstructionNowWithRemainingCount();//6
    //1
    withMisfireHandlingInstructionFireNow  ---> misfireInstruction == 1
    ——以当前时间为触发频率立即触发执行
    ——执行至FinalTIme的剩余周期次数
    ——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
    ——调整后的FinalTime会略大于根据starttime计算的到的FinalTime
    //2
    withMisfireHandlingInstructionIgnoreMisfires ---> misfireInstruction == -1
    —以错过的第一个频率时间立刻开始执行
    ——重做错过的所有频率周期
    ——当下一次触发频率发生时间大于当前时间以后,按照Interval的依次执行剩下的频率
    ——共执行RepeatCount+1
    //3
    withMisfireHandlingInstructionNextWithExistingCount ---> misfireInstruction == 5
    ——不触发立即执行
    ——等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数
    ——以startTime为基准计算周期频率,并得到FinalTime
    ——即使中间出现pauseresume以后保持FinalTime时间不变
    //4
    withMisfireHandlingInstructionNextWithRemainingCount ---> misfireInstruction = 4
    ——不触发立即执行
    ——等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数
    ——以startTime为基准计算周期频率,并得到FinalTime
    ——即使中间出现pauseresume以后保持FinalTime时间不变
    //5
    withMisfireHandlingInstructionNowWithExistingCount ---> misfireInstruction = 2
    ——以当前时间为触发频率立即触发执行
    ——执行至FinalTIme的剩余周期次数
    ——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
    ——调整后的FinalTime会略大于根据starttime计算的到的FinalTime
    //6
    withMisfireHandlingInstructionNowWithRemainingCount --- >misfireInstruction = 3
    ——以当前时间为触发频率立即触发执行
    ——执行至FinalTIme的剩余周期次数
    ——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
    ——调整后的FinalTime会略大于根据starttime计算的到的FinalTime

    MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT 值为 3
    ——此指令导致trigger忘记原始设置的starttimerepeat-count
    ——触发器的repeat-count将被设置为剩余的次数
    ——这样会导致后面无法获得原始设定的starttimerepeat-count

updateAfterMisfire 方法源码:

    /**
         * <p>
         * Updates the <code>SimpleTrigger</code>'s state based on the
         * MISFIRE_INSTRUCTION_XXX that was selected when the <code>SimpleTrigger</code>
         * was created.
         * </p>
         * 
         * <p>
         * If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY,
         * then the following scheme will be used: <br>
         * <ul>
         * <li>If the Repeat Count is <code>0</code>, then the instruction will
         * be interpreted as <code>MISFIRE_INSTRUCTION_FIRE_NOW</code>.</li>
         * <li>If the Repeat Count is <code>REPEAT_INDEFINITELY</code>, then
         * the instruction will be interpreted as <code>MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT</code>.
         * <b>WARNING:</b> using MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 
         * with a trigger that has a non-null end-time may cause the trigger to 
         * never fire again if the end-time arrived during the misfire time span. 
         * </li>
         * <li>If the Repeat Count is <code>> 0</code>, then the instruction
         * will be interpreted as <code>MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT</code>.
         * </li>
         * </ul>
         * </p>
         * */
    /*
    基于在创建SimpleTrigger时选择的MISFIRE_INSTRUCTION_XXX更新SimpleTrigger的状态。
    如果失火指令设置为MISFIRE_INSTRUCTION_SMART_POLICY,则将使用以下方案:

    •如果重复计数为0,则指令将解释为MISFIRE_INSTRUCTION_FIRE_NOW。
    •如果重复计数为REPEAT_INDEFINITELY,则指令将解释为MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT。 警告:如果触发器具有非空的结束时间,则使用MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT可能会导致触发器在失火时间范围内到达结束时,不会再次触发。
    •如果重复计数大于0,则指令将解释为MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT。
    */
    @Override
    public void updateAfterMisfire(Calendar cal) {
        int instr = getMisfireInstruction();//获取misfire的值,默认为0

        if(instr == Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY)//instr == -1
            return;

        if (instr == Trigger.MISFIRE_INSTRUCTION_SMART_POLICY) { //instr == 1
            if (getRepeatCount() == 0) {
                instr = MISFIRE_INSTRUCTION_FIRE_NOW; //instr = 1
            } else if (getRepeatCount() == REPEAT_INDEFINITELY) {//getRe..Count == -1
                //instr = 4
                instr = MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT;
            } else {
                // if (getRepeatCount() > 0)
                instr = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT;//instr == 2
            }
            //instr  == 1
        } else if (instr == MISFIRE_INSTRUCTION_FIRE_NOW && getRepeatCount() != 0) {
            //instr  == 3
            instr = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT;
        }

        if (instr == MISFIRE_INSTRUCTION_FIRE_NOW) { //instr  == 1
            setNextFireTime(new Date());
            //instr  == 5
        } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT) {
            Date newFireTime = getFireTimeAfter(new Date());
            while (newFireTime != null && cal != null
                   && !cal.isTimeIncluded(newFireTime.getTime())) {
                newFireTime = getFireTimeAfter(newFireTime);

                if(newFireTime == null)
                    break;

                //avoid infinite loop
                java.util.Calendar c = java.util.Calendar.getInstance();
                c.setTime(newFireTime);
                if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) {
                    newFireTime = null;
                }
            }
            setNextFireTime(newFireTime);
            //instr  == 4
        } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT) {
            Date newFireTime = getFireTimeAfter(new Date());
            while (newFireTime != null && cal != null
                   && !cal.isTimeIncluded(newFireTime.getTime())) {
                newFireTime = getFireTimeAfter(newFireTime);

                if(newFireTime == null)
                    break;

                //avoid infinite loop
                java.util.Calendar c = java.util.Calendar.getInstance();
                c.setTime(newFireTime);
                if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) {
                    newFireTime = null;
                }
            }
            if (newFireTime != null) {
                int timesMissed = computeNumTimesFiredBetween(nextFireTime,
                                                              newFireTime);
                setTimesTriggered(getTimesTriggered() + timesMissed);
            }

            setNextFireTime(newFireTime);
        } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT) { //instr  == 2
            Date newFireTime = new Date();
            if (repeatCount != 0 && repeatCount != REPEAT_INDEFINITELY) {
                setRepeatCount(getRepeatCount() - getTimesTriggered());
                setTimesTriggered(0);
            }

            if (getEndTime() != null && getEndTime().before(newFireTime)) {
                setNextFireTime(null); // We are past the end time
            } else {
                setStartTime(newFireTime);
                setNextFireTime(newFireTime);
            } 
        } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT) { //instr  == 3
            Date newFireTime = new Date();

            int timesMissed = computeNumTimesFiredBetween(nextFireTime,
                                                          newFireTime);

            if (repeatCount != 0 && repeatCount != REPEAT_INDEFINITELY) { //repeatCount == -1
                int remainingCount = getRepeatCount()
                    - (getTimesTriggered() + timesMissed);
                if (remainingCount <= 0) { 
                    remainingCount = 0;
                }
                setRepeatCount(remainingCount);
                setTimesTriggered(0);
            }

            if (getEndTime() != null && getEndTime().before(newFireTime)) {
                setNextFireTime(null); // We are past the end time
            } else {
                setStartTime(newFireTime);
                setNextFireTime(newFireTime);
            } 
        }

    }

二、CronTrigger的misfire机制—-默认的 Trigger.MISFIRE_INSTRUCTION_SMART_POLICY !!!

trig.updateAfterMisfire(cal);
getMisfireInstruction() —-> misfireInstruction == 0

    CronScheduleBuilder csb = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");

    csb.withMisfireHandlingInstructionDoNothing();
    csb.withMisfireHandlingInstructionFireAndProceed();
    csb.withMisfireHandlingInstructionIgnoreMisfires();
    withMisfireHandlingInstructionDoNothing ---> misfireInstruction = 2
    ——不触发立即执行
    ——等待下次Cron触发频率到达时刻开始按照Cron频率依次执行
    withMisfireHandlingInstructionFireAndProceed ---> misfireInstruction = 1
    ——以当前时间为触发频率立刻触发一次执行
    ——然后按照Cron频率依次执行
    withMisfireHandlingInstructionIgnoreMisfires ---> misfireInstruction = -1
    ——以错过的第一个频率时间立刻开始执行
    ——重做错过的所有频率周期后
    ——当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行

updateAfterMisfire 方法源码:

    /**
         * <p>
         * Updates the <code>CronTrigger</code>'s state based on the
         * MISFIRE_INSTRUCTION_XXX that was selected when the <code>CronTrigger</code>
         * was created.
         * </p>
         * 
         * <p>
         * If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY,
         * then the following scheme will be used: <br>
         * <ul>
         * <li>The instruction will be interpreted as <code>MISFIRE_INSTRUCTION_FIRE_ONCE_NOW</code>
         * </ul>
         * </p>
         */
    /*
        根据创建CronTrigger时选择的MISFIRE_INSTRUCTION_XXX更新CronTrigger的状态。

    如果失火指令设置为MISFIRE_INSTRUCTION_SMART_POLICY,则将使用以下方案:

    •指令将解释为MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
    */

    @Override
    public void updateAfterMisfire(org.quartz.Calendar cal) {
        int instr = getMisfireInstruction();//获取misfire的值,默认为0

        if(instr == Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY)//instr  == -1
            return;

        if (instr == MISFIRE_INSTRUCTION_SMART_POLICY) {//instr  == 0
            instr = MISFIRE_INSTRUCTION_FIRE_ONCE_NOW;//instr = 1
        }

        if (instr == MISFIRE_INSTRUCTION_DO_NOTHING) {//instr  == 2
            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) {//instr  == 1
            setNextFireTime(new Date());
        }
    }

作者:阿飞云 | 来源:https://blog.csdn.net/u010648555/column/info/14251

赞(1) 打赏
版权归原创作者所有,任何形式转载请联系作者;码农code之路 » Quartz源码(四):Quartz调度器的Misfire处理规则

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏