历时一个月,才定位到quartz任务偶尔执行失败问题

前言

本片文章主要介绍了,实际开发中因为项目架构的问题,引发的一系列让人摸不做头脑的问题。实际上不是技术框架bug,和开发同事的写法问题。

问题的前因后果:

今年的项目的定时任务都是用的quartz框架。在开发过程中,没遇到啥问题。但是测试在测试的时候,出现定时任务偶尔不执行,定时任务执行报错。 最开始在测试环境有这个报错的问题,估计定时任务是其他人的电脑在执行(当时问了开发他们说他们没启动)。

这样过了大半个月,测试发现在生产上也出现定时任务不执行,执行报错的问题,而且我们同事还在说,我明明改了代码,本地也没问题,但是生产还是执行的以前的逻辑呢,给技术领导反馈了,也不知道咋回事。因为这半个月以来我一直在看quartz框架的原理,还写过相关文章【quartz在springboot中启动流程】。大家都发现了定时任务有问题,这也激发了我的兴趣。因为有了知识储备,所以我也是解决的这两个问题。


原因分析:

  1. 定时任务偶尔不执行 首先这个并不是任务没有执行,而是没有捕捉异常,没有去更新数据状态导致的。下面看看代码吧

    java 复制代码
      @Override
      public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
      	//查询需要到执行导出的任务
        List<ExportRecord> unionImportExportVos = service.getExportingRecord();
        ExportService exportService = null;
        for (ExportRecord record : unionImportExportVos) {
        //获取实现类
          exportService = (UnionExportService) applicationContext.getBean(record.getImplementBeanName());
          //实现类执行导出任务,导出成功更新 record 导出状态
          exportService.exportData(unionImporExportVo.getId());
        }
      }

    由于实现类是由多个人写的,有些没有捕捉异常,并且excute接口也没有去捕捉异常,导致ExportRecord的状态一直是导出中,让测试觉得定时任务没有执行。

    所以第一个问题是在各自的实现类、以及execute方法里面 增加捕捉异常,并且更新record为失败的状态。

    改了之后,偶尔还是会出现问题,并且从来没有找到过日志。分析下面几个问题时会找到没有没有报错日志的原因。

  2. 改了代码,生产环境还是执行以前的逻辑 听见同事在反馈,这时我已经对quartz有了一定的了解。回头再去排查,就找到了根本原因。不是代码的问题,是系统架构问题,还有另一个系统也在跑我们的的定时任务

    说一下为什么另一个项目为什么会跑我们的项目吧,因为这两个项目用的是统一套代码,同一个数据库。只是在表上面加了前缀做了隔离,但是定时任务内部实际记录任务状态的表又没有加前缀。所以两个任务串门了。

    当时同事和技术leader说明的时候,他们说加了前缀的,实际上加了前缀的这个表不是quartz框架内部的,只是第三方框架对外暴露对定时任务进行增删改查的表。

  3. 定时任务偶尔报错,找不到用户信息。 解决了同事代码没生效问题(改了定时任务两个项目都打包就没问题了),发现我的定时还是出现找不到用户信息的错误。最开始我以为我的写法有问题,userId 存到TheadLocalMap中,后面加了日志发现实在查询数据库的时候mapper.selectById(userId) 没有查询到。去数据库查却有,没错出现这个问题还是因为在两个项目用的同一套代码的问题。导致这个mapper也给老子用串了,查到另一个项目的user表了。

    最后还是把定时任务这块完全独立开了,但是代码用的是一个git,两个项目模块存在互相调用的情况,因此估计后续还可能出现其他问题。(比如出现要使用到两个系统同名的表,并且mapper名称一样,这时候系统就查自己的表去了)


解决方案:

将Quartz相关所有的表都彼此独立开,就解决了quartz任务执行串门的问题。 主要还是项目架构出了大问题(两个项目用一套代码,只是分布在不同的module,连数据库都用的一样,只是加了前缀做区分,打包的时候两个模块的代码都打进去了),估计后面还会踩很多坑。

根本原因

项目架构设计出了问题。

为什么要这样做呢? 当时本来是两个项目,在开发第二项目的时候发现要频繁调用第一个项目的接口,有没有用微服务,用http太麻烦了。没办法就把两个项目的代码合到一起了,但是部署、表还是分开的。 有人说为啥当时不做到一个项目呢? 哈哈。因为当时业务领导的指导思想是,我每个子系统都要能独立运行,都要可以直接售卖。而且开发的时候,我们也没有项目设计时间,拿到就开整

相关推荐
SL_staff6 小时前
3天上线OKR系统:一名HR与1名工程师如何用JVS完成全栈交付
java·低代码·开源
wzdark7 小时前
基于链表的内存池设计与内存复用机制4
java·数据结构·链表
cnkeysky7 小时前
idea 中的 maven 项目重新加载子模块
java·idea
Escalating_xu8 小时前
【System V 信号量】从 P/V 原语到 Builder 封装:写出可控、可清理的进程互斥组件
java·linux·开发语言·jvm
今天AI了吗8 小时前
什么是 AI Agent?它与直接调用大模型 API 有何区别
java·网络·人工智能·架构·java-ee
隐退山林8 小时前
JavaEE进阶:SpringAOP
java·java-ee
Wang's Blog8 小时前
Java框架快速入门: Spring Security+OAuth2之方法级安全注解
java·安全·spring
JavacKaka8 小时前
LiteFlow规则引擎实战博客-2026-09-09
java
学渣超8 小时前
记一次复杂业务功能重构——从过程式长链路,到模板方法构建体系
java·架构·代码规范
Bs_MoneyMagnet9 小时前
基于springboot+vue的旅游景区点评系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring·旅游