SpringBoot中定时任务踩坑,@Scheduled重复执行问题排查(看完直接破防)

前言

今天再开发业务需求的过程中,需要用到定时任务,原本定的是每10分钟推送一次,可是当每次十分钟到的时候,定时任务就会推送多条!但是非常奇怪的是,本地调试的时候不会有问题,只有当你部署到到服务器上的时候才会暴露这个问题!!!!

如图: 这些消息都是一次性推送出来的,本来他们应该只有一条被推送出来的,可是现在他们却全都出来了,难道真是"一家人就要整整齐齐"吗?

解决思路

这种本地无法重现的问题解决起来最恼火了,于是乎我去网上寻找答案,看看有没有人遇到类似的情况! 其中两篇是这么说的:

文章连接:生产问题:@Scheduled Spring定时任务每次执行两次原因分析以及解决方案

文章连接:spring定时任务执行两次的原因与解决方法

他们的大概的意思就是因为他的配置到导致他的配置类被重复加载了两次,进而导致定时任务重复执行多次!

于是我就类比了一下,看到在我的项目中,确实使用了@EnableScheduling两次

第一次:

第二次:

于是我赶紧把启动类上的@EnableScheduling注解去掉,并祈祷能有用!

结果如我所料,果然没什么用!

于是我继续搜索,看到这样一篇文章:

当我看到这句话的时候,我甚至以为我已经接近真理了! springboot关于定时任务执行多次的问题 但是当我看到他写的这些太乱了,而且一个简答的定时任务,被他搞得这么复杂,我果断放弃了。

头痛砍头????

我于是乎又接着找,我发现了这样一篇文章,特别逆天!!!

Springboot 使用 @Scheduled 定时任务生产环境执行两次 好家伙,你这好比你去医院看病,你和医生说:"医生我头痛,我该怎么办?",医生说:"没事的哈,一会去把把头砍了,砍了就不痛了哈!"

接近真理

时间在一分一秒的过去,我却毫无紧张,甚至已经开始汗流浃背了,从未感到如此巨大之强度,于是乎我便去到了stackoverflow上搜索一下看看!

哎!你说好巧不巧,还真就让我找到问题了! 看到这样一条问题:

这不就是我遇到的问题吗?

他是这么说的:

I have a service which has to run a job to get and refresh it's data from another service. The job has to be run on startup and every couple of hours/days. I was looking into the behavior of the scheduled job and it seems to be called two times consecutively according to the logs (see below).

我们来看他给的代码:

java 复制代码
@Service
public class ServiceImpl implements ServiceInterface {

@Autowired
private FetchService fetchService;

private int timesCalled = 0;
private Data data;

@PostConstruct
private void initialize() {
    data = fetchService.getAndUpdate();
}

@Scheduled(cron = "* */5 * * * *")
private void refresh() {
    LOG.info(appContext.getId());
    LOG.info("This object: " + System.identityHashCode(this));
    LOG.info("Times called: " +  timesCalled);
    timesCalled++;
    data = fetchService.getAndUpdate();
}

日志信息:

yaml 复制代码
2020-07-02 17:30:00.006  INFO 30416 --- [   scheduling-1] c.d.p.d.service.ServiceImpl  : org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6db9cae5
2020-07-02 17:30:00.006  INFO 30416 --- [   scheduling-1] c.d.p.d.serice.ServiceImpl  : This object: 357813323
2020-07-02 17:30:00.006  INFO 30416 --- [   scheduling-1] c.d.p.d.service.ServiceImpl  : Times called: 1
....
2020-07-02 17:30:32.001  INFO 30416 --- [   scheduling-1] c.d.p.d.service.ServiceImpl  : org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6db9cae5
2020-07-02 17:30:32.001  INFO 30416 --- [   scheduling-1] c.d.p.d.service.ServiceImpl  : This object: 357813323
2020-07-02 17:30:32.001  INFO 30416 --- [   scheduling-1] c.d.p.d.service.ServiceImpl  : Times called: 2

然后就有网友给他解释道:正如你所写的,你的cron表达式是 * */5 * * * * ,这意味着,根据Spring指南,它将每隔5分钟运行一次:

你写的代码不就是下面这样吗?

java 复制代码
@Scheduled(cron = "* */5 * * * *")
private void refresh() {
    log.info("Times called: " +  timesCalled);
    timesCalled++;
}

我们来测试一下吧:

yaml 复制代码
14:20:13.001  INFO 8980 --- [   sch-1] com.example.demo.Sched   : Times called: 13
14:20:14.001  INFO 8980 --- [   sch-1] com.example.demo.Sched   : Times called: 14
14:20:15.003  INFO 8980 --- [   sch-1] com.example.demo.Sched   : Times called: 15
14:20:59.002  INFO 8980 --- [   sch-1] com.example.demo.Sched   : Times called: 59
14:25:00.000  INFO 8980 --- [   sch-1] com.example.demo.Sched   : Times called: 60
14:25:01.000  INFO 8980 --- [   sch-1] com.example.demo.Sched   : Times called: 61
14:25:02.001  INFO 8980 --- [   sch-1] com.example.demo.Sched   : Times called: 62
14:25:03.002  INFO 8980 --- [   sch-1] com.example.demo.Sched   : Times called: 63

从日志我们可以看出,他确实是在每五分钟执行一次,可是执行完了,他在第五分钟内还将重复执行!所以我们会看到业务代码被执行了很多次!如果你想每五分钟只执行一次的话,你应该这样写:@Scheduled(cron = "0 */5 * * * *")

成功解救

我一看我的代码也是这样写的:

赶紧改过来,问题就解决了!这下对spring的corn表达式理解又加深了!同时有问题可去stackoverflow上搜一下,很有用!!

最后的疑问

为什么本地调试我0 */5 * * * *这样写和* */5 * * * *都只执行一次,而到线上的时候就会执行多次,有谁能知道这是为什么?

本文由mdnice多平台发布

相关推荐
计算机毕设指导628 分钟前
基于Springboot学生宿舍水电信息管理系统【附源码】
java·spring boot·后端·mysql·spring·tomcat·maven
计算机-秋大田35 分钟前
基于Spring Boot的兴顺物流管理系统设计与实现(LW+源码+讲解)
java·vue.js·spring boot·后端·spring·课程设计
羊小猪~~2 小时前
MYSQL学习笔记(九):MYSQL表的“增删改查”
数据库·笔记·后端·sql·学习·mysql·考研
豌豆花下猫2 小时前
Python 潮流周刊#90:uv 一周岁了,优缺点分析(摘要)
后端·python·ai
橘猫云计算机设计3 小时前
基于SSM的《计算机网络》题库管理系统(源码+lw+部署文档+讲解),源码可白嫖!
java·数据库·spring boot·后端·python·计算机网络·毕设
熬夜苦读学习3 小时前
Linux文件系统
linux·运维·服务器·开发语言·后端
坚定信念,勇往无前4 小时前
Spring Boot 如何保证接口安全
spring boot·后端·安全
程序员侠客行5 小时前
Spring事务原理详解 三
java·后端·spring·架构
Hello.Reader6 小时前
深入理解 Rust 的 `Rc<T>`:实现多所有权的智能指针
开发语言·后端·rust
yoona10206 小时前
Rust编程语言入门教程(八)所有权 Stack vs Heap
开发语言·后端·rust·区块链·学习方法