【若依】定时任务问题:关闭了定时任务,但是依然在跑,且同一时刻跑了多条记录,为什么?

文章讨论了两个问题:1)单体/集群项目中,定时任务关闭后仍运行,源于内存缓存未清空;解决办法是刷新服务器内存或重启部署。2)同一时刻定时任务重复执行导致幂等问题,需结合业务场景确保同一节点执行,如发送短信避免重复。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题1

描述:

定时任务关闭了, 但是服务器定时任务依然在跑

原因:

若依自带定时任务有缓存,且缓存是服务器内存,不是分布式缓存。

  • 单体项目:

    很可能是手动修改了数据库表中的定时任务开关,但是缓存没有关闭。

  • 集群项目:

    项目部署在多个节点上,且每个节点绑定的数据库表是同一张表;

    若依框架定时任务使用的调度器缓存是服务器内存,不是分布式缓存,所以在节点1 关闭定时任务,节点2查看的时候,展示的是关闭,但是实际上节点2内存中的开关缓存依然是开,所以结点2依然会跑。

办法:

刷新服务器内存中的缓存;

操作:

  • 单体项目:

    重新开启-再关闭;或者重新构建服务器部署;

  • 集群项目:(k8s项目部署多个节点)

    每个节点重新开启-再关闭;或者重新构建每个节点的服务器部署;

问题2

描述:

同一时刻,定时任务执行了多次;执行多次结果幂等(比如:单据本来就因为业务原因同步系统1失败,你再执行,它结果还是失败)

原因:

下面这段代码是定时任务调用的同步失败问题订单的服务方法:

    public void synSrmProblemOrderFail() throws Exception {
        String key = RedisKeyPre.inventorySrmProblem;
        RLock rLock = redissonClient.getLock(key);
        try {
            // 尝试加锁,最多等待3秒,上锁以后300秒自动解锁
            boolean res = rLock.tryLock(3, 300, TimeUnit.SECONDS);
            if (!res) {
                Log.info(LogBuilder.builder().business("同步SRM问题单,请等待锁释放").build());
                return;
            }
        } catch (InterruptedException e) {
            Log.error(LogBuilder.builder().business("同步SRM问题单获取锁异常" + e).build());
        }
        try {
            qmsAsyncTaskService.synSrmProblemOrderFail();
        } finally {
            releaseLock(rLock);
        }
    }

上面代码对应出现定时任务一个时刻时,执行多次场景(项目部署在多个节点):
image-20231012090415099

  • 注意:这里如果多个节点系统时间不一致时,考虑是否节点执行是否同频,以造成这个结果;

办法:

结合业务场景考虑:是否确保同一时刻只有一个结点在同步;

比如:类似发短信的定时任务,每天10点给客户发,结果你这个10点给客户发了多条,这就不行了;

不过,还有一种场景,就是同步失败单据,虽然结果会出现幂等(业务原因同步失败的单据,你同步多少次都是失败),但是对于网络原因失败的,可以每个节点都执行时,也可以考虑不处理;

  • 如果要确保同一时刻只有一个结点执行,需要优化代码

    image-20231012091715433

### 若依定时任务未执行原因分析 若依框架中的定时任务通常基于Spring Task或Quartz实现。如果发现定时任务未能正常执行,可能涉及多个方面的原因及其对应的解决方案。 #### 1. **调度器状态异常** 如果调度器处于关闭或禁用状态,则可能导致定时任务无法触发。这类似于Oracle快照备用数据库中遇到的问题[^1]。 - 检查配置文件`application.yml`或`application.properties`中是否启用了定时任务功能: ```yaml spring: task: scheduling: enabled: true ``` - 确认项目启动日志中是否存在关于调度器初始化成功的记录。如果没有找到相关日志,说调度器可能未成功加载。 #### 2. **任务注解缺失或错误** Spring Task依赖于特定的注解来识别和管理定时任务。如果注解使用不当,可能会导致任务失效。 - 确保目标方法上标注了`@Scheduled`注解,并正确设置了参数(如cron表达式)。例如: ```java @Scheduled(cron = "0/5 * * * * ?") // 每隔5秒执行一次 public void scheduledTask() { System.out.println("定时任务正在运行..."); } ``` #### 3. **环境变量冲突** 部署环境中可能存在某些干扰因素影响到定时任务的正常运行。例如,在多节点部署场景下,若缺乏协调机制,容易引发重复执行或其他异常行为[^3]。 - 可考虑引入分布式锁技术,确保同一时刻仅有一个实例能够真正执行该任务。具体法可以借助Redis等中间件实现互斥控制。 #### 4. **脚本权限不足** 类似于Linux下的Crontab任务不执行情况,有时候是因为脚本本身缺少必要的执行权限所致[^4]。 - 对应至Java应用层面,需核实是否有足够的资源访问许可去完成预定操作;另外还需注意网络连通性和外部服务可用性等因素的影响。 #### 5. **时间设置不合理** 使用Quartz组件构建复杂计划表时,如果不小心定义了一个永远不会到达的时间点,那么相应作业自然也就不会被执行出来[^2]。 --- ### 综合排查建议 针对上述提到的各种可能性逐一验证并调整直至恢复正常运作为止: - 复核所有基础设定项; - 测试单一最简化版本确认基本流程通畅后再逐步叠加额外条件; - 查阅官方文档获取更详尽指导信息。 ```java // 示例代码片段展示如何声一个简单的周期型任务 @Component public class MyScheduler { private static final Logger logger = LoggerFactory.getLogger(MyScheduler.class); @Scheduled(fixedRate = 1000L) public void performAction(){ logger.info("每秒钟打印一条消息"); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码元宋大米

感谢小主大赏,留言可进互助群~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值