历时一个月,才定位到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太麻烦了。没办法就把两个项目的代码合到一起了,但是部署、表还是分开的。 有人说为啥当时不做到一个项目呢? 哈哈。因为当时业务领导的指导思想是,我每个子系统都要能独立运行,都要可以直接售卖。而且开发的时候,我们也没有项目设计时间,拿到就开整

相关推荐
anew___26 分钟前
《从零手写操作系统 (20):ELF加载器——让OS读懂现代编译器》
java·服务器·前端
code2cat27 分钟前
【随笔】MCP资源更新订阅:通知到达以后,Agent怎样刷新旧资料
java·后端·开发工具·ai agent·mcp
一只旭宝1 小时前
C++ 后端开发面试题整理
java·c++·面试
sunshine22 girl1 小时前
Java学习五 面向对象高级5 内部类3-静态内部类和局部内部类(了解)
java·学习
en.en..1 小时前
Linux 进程退出exit(函数)
java·开发语言·算法
李游Leo1 小时前
HarmonyOS 7 TaskPool + Node-API + zstd:Native 批量压缩任务的主线程隔离、进度回传与资源收口【鸿蒙心迹】
java·华为·harmonyos
Light Gao1 小时前
Encoder 与 Decoder 详解:从 Embedding 到 Seq2Seq 的完整数据流
java·开发语言·embedding
程序猿乐锅2 小时前
【黑马点评 | 第十一篇】关注 Feed 流实现
java·数据库·redis·分布式·后端·缓存·maven
开开心心就好2 小时前
图片白底怎么去掉?抠图工具抠完背景透明
java·服务器·开发语言·pdf·ocr·散列表·启发式算法
东方芷兰2 小时前
Agent 技术摘要 05 —— BP、SaaS、B2B、C2B、B2C
java·笔记·python·语言模型·自然语言处理