You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot启动Quartz集群报找不到Trigger记录的Misfire错误

Quartz集群启动时Misfire处理报找不到Trigger记录的解决方案

问题根因

这个报错是集群模式下Quartz多线程并行操作的时序不一致导致的,触发链路如下:

  1. 启动监听方法加了@Async注解,业务侧调度单次任务的逻辑和Quartz自身的Misfire扫描、任务调度流程完全并行执行
  2. 业务代码创建的是startAt(new Date())的立即执行单次任务,Trigger记录写入QRTZ_TRIGGERS、QRTZ_SIMPLE_TRIGGERS表后,会被调度线程立刻捞取执行,执行完成后Quartz会自动删除这两张表中对应单次任务的记录(repeatCount=0的任务执行完无留存)
  3. MisfireHandler轮询扫错过执行时间的任务时,刚好在任务删除前从QRTZ_TRIGGERS表读到了该Trigger的记录,等它再去QRTZ_SIMPLE_TRIGGERS查详情时,调度线程已经把关联记录删完了,就会抛出找不到记录的异常
  4. 配置中misfireThreshold=60000(1分钟阈值)、集群节点启动时间差、业务分布式锁不控制Quartz内部线程启动时机,都会放大这个问题的出现概率。

这个异常本身不影响业务逻辑,既不会导致任务漏执行,也不会造成数据脏写,只是会打印错误日志。

修复方案

按优先级从高到低选择即可:

  • 调整Quartz启动时序,从根源上避免并行冲突
    配置Spring Boot关闭Quartz自动启动:
    spring.quartz.auto-startup=false
    
    把init方法上的@Async注解去掉,在init方法内所有业务逻辑、任务调度操作全部完成后,手动启动Quartz调度器:
    @EventListener(ApplicationReadyEvent.class)
    @DLockAcquired(keyName = "datasource-init")
    public void init() {
      logger.info("Initialize Synchronize datasource on startup ...");
      try {
        this.doSyncDatasource();
      } catch (Exception e) {
        logger.error("Initialize datasource failed, error: ", e);
      }
      aferInitialize.set(true);
      // 所有任务调度完成后再启动Quartz
      schedulerFactoryBean.getScheduler().start();
    }
    
  • 优化单次任务的Trigger配置,降低时序冲突概率
    给立即执行的单次任务留少量启动缓冲,同时显式配置misfire忽略策略,避免已删除的任务进入misfire处理流程:
    public void scheduleJobOnce(JobDetail jobDetail, TriggerKey triggerKey)
        throws SchedulerException {
      Scheduler scheduler = schedulerFactoryBean.getScheduler();
      Trigger simpleTrigger = TriggerBuilder.newTrigger()
          // 留1.5s缓冲,避免刚写入就被判定为misfire
          .startAt(new Date(System.currentTimeMillis() + 1500))
          .withIdentity(triggerKey)
          .withSchedule(SimpleScheduleBuilder.simpleSchedule()
              .withRepeatCount(0)
              // 单次任务错过触发直接丢弃,不走misfire恢复
              .withMisfireHandlingInstructionIgnoreMisfires()
          ).build();
      try {
        scheduler.scheduleJob(jobDetail, simpleTrigger);
      } catch (SchedulerException e) {
        logger.error("Quartz schedule job failed, {}.",
            JsonUtil.parseObjectToString(jobDetail.getJobDataMap()), e);
        throw e;
      }
    }
    
  • 兜底容错处理
    如果不想调整现有逻辑,可以继承LocalDataSourceJobStore重写recoverMisfiredJobs方法,捕获Trigger找不到的异常,打debug日志后直接跳过,不要抛出错误日志即可。

内容的提问来源于stack exchange,提问作者leo.li

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 16:21:32