目录

Quartz失火指令、补偿执行机制配置

处理规则

调度(scheduleJob)或恢复调度(resumeTrigger,resumeJob)后不同的misfire对应的处理规则如下:

CronTrigger

  • withMisfireHandlingInstructionDoNothing

    • 不触发立即执行
    • 等待下次Cron触发频率到达时刻开始按照Cron频率依次执行
  • withMisfireHandlingInstructionIgnoreMisfires

    • 以错过的第一个频率时间立刻开始执行
    • 重做错过的所有频率周期后
    • 当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行
  • withMisfireHandlingInstructionFireAndProceed

    • 以当前时间为触发频率立刻触发一次执行
    • 然后按照Cron频率依次执行

SimpleTrigger

  • withMisfireHandlingInstructionFireNow

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

    • 以错过的第一个频率时间立刻开始执行
    • 重做错过的所有频率周期
    • 当下一次触发频率发生时间大于当前时间以后,按照Interval的依次执行剩下的频率
    • 共执行RepeatCount+1次
  • withMisfireHandlingInstructionNextWithExistingCount

    • 不触发立即执行
    • 等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数
    • 以startTime为基准计算周期频率,并得到FinalTime
    • 即使中间出现pause,resume以后保持FinalTime时间不变
  • withMisfireHandlingInstructionNowWithExistingCount

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

    • 不触发立即执行
    • 等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数
    • 以startTime为基准计算周期频率,并得到FinalTime
    • 即使中间出现pause,resume以后保持FinalTime时间不变
  • withMisfireHandlingInstructionNowWithRemainingCount

    • 以当前时间为触发频率立即触发执行
    • 执行至FinalTIme的剩余周期次数
    • 以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
    • 调整后的FinalTime会略大于根据starttime计算的到的FinalTime值MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
    • 此指令导致trigger忘记原始设置的starttime和repeat-count
    • 触发器的repeat-count将被设置为剩余的次数
    • 这样会导致后面无法获得原始设定的starttime和repeat-count值

示例代码

示例代码为CronTrigger

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
interface QuartzSchedulerService {

    enum class CronMisfireInstruction {
        WithMisfireHandlingInstructionDoNothing, // 忽略,等待下次Cron触发频率到达时刻开始按照Cron频率依次执行
        WithMisfireHandlingInstructionFireAndProceed, // 以当前时间为触发频率立刻触发一次执行,然后按照Cron频率依次执行(默认)
        WithMisfireHandlingInstructionIgnoreMisfires // 以错过的第一个频率时间立刻开始执行, 重做错过的所有频率周期后, 当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行
    }
    fun submitJob(jobName: String, jobGroupName: String, jobClazz: Class<out Job>, jobDataMap: JobDataMap,
                  cronExpression: String, cronMisfireInstruction: CronMisfireInstruction): Boolean
    
}


@Service
class QuartzSchedulerServiceImpl(
        var scheduler: Scheduler
) : QuartzSchedulerService {

    private val log: Logger = LoggerFactory.getLogger(this.javaClass)

    override fun submitJob(jobName: String, jobGroupName: String, jobClazz: Class<out Job>, jobDataMap: JobDataMap, cronExpression: String,
                           cronMisfireInstruction: QuartzSchedulerService.CronMisfireInstruction): Boolean {
        val jobKey = JobKey.jobKey(jobName, jobGroupName)
        scheduler.getJobDetail(jobKey).let {
            this.removeJob(jobName, jobGroupName) // 定时任务已存在,先删除。
        }

        try {
            // 任务名,任务组,任务执行类
            val jobDetail = JobBuilder.newJob(jobClazz)
                    .withIdentity(jobName, jobGroupName)
                    .usingJobData(jobDataMap)
                    .build()

            // 配置失火指令
            val cronSchedule = CronScheduleBuilder.cronSchedule(cronExpression)
            when (cronMisfireInstruction) {
                QuartzSchedulerService.CronMisfireInstruction.WithMisfireHandlingInstructionDoNothing -> {
                    cronSchedule.withMisfireHandlingInstructionDoNothing()
                }
                QuartzSchedulerService.CronMisfireInstruction.WithMisfireHandlingInstructionIgnoreMisfires -> {
                    cronSchedule.withMisfireHandlingInstructionIgnoreMisfires()
                }
                QuartzSchedulerService.CronMisfireInstruction.WithMisfireHandlingInstructionFireAndProceed -> {
                    cronSchedule.withMisfireHandlingInstructionFireAndProceed()
                }
            }

            // 触发器名称,触发时间
            val cronTrigger = TriggerBuilder.newTrigger()
                    .withIdentity(jobName, jobGroupName)
                    .startNow()
                    .withSchedule(cronSchedule)
                    .build()

            // 加入调度器容器
            scheduler.scheduleJob(jobDetail, cronTrigger)
            log.info("已向调度服务器添加任务:[$jobGroupName]($jobName)")
        } catch (e: Throwable) {
            throw BusinessException("添加任务[$jobGroupName]($jobName)到调度服务器失败")
        }
        // 启动调度器
        return this.start()
    }
}

评论