一次XxlJob调度任务重复执行的问题排查

news2024/11/19 17:20:04

目录

    • 东老师的问题
        • 1. 为什么会重复执行
        • 2. 为什么时间间隔改为1min就不会重复执行**
    • 开始排查
      • 先看下任务配置
    • 任务第一次执行
      • 排查执行类 ==》`JobThread`
      • JobThread的核心逻辑
          • 1.循环消费 一个阻塞队列 不断的去消费队列中TriggerParam 这个参数
          • 2.看下TriggerParam,这正是我们在admin控制台配置的参数生成的实体
          • 3.核心执行逻辑是下面两个执行点
          • 第一个问题的结论
          • 第一个问题已经解决,那么为什么频率1min就不重复执行呢。
      • 总结

东老师的问题

东东老师:浪浪老师,我有问题了
我赶紧远离东老师:你有问题你去找路边的老中医广告的联系方式,什么延时、助勃、药到病除、金枪不倒,
那才是专业的,我不是你们那圈子的人
东东老师一挥手:我不是说这个,我的这边开发出了点问题,哦,还有你这个老中医的广告贴哪儿了,乱贴小广告不好,我去给它揭了
我:

害,吓我一跳,我以为东老师你终于要对我下手了呢
你QA开发能有啥问题

东老师:

是这样的,这次需求嘛 我开发了个定时任务用来清洗数据,使用的xxl-job,版本是XXXX,执行倒是没问题,问题是重复执行了

我立马摆摆手:

东老师你是知道我的,我从来不看框架源码,向来一把梭

东老师很爽快:

今天星期四,我kfc快到了

我:

东老师 你可是我异父异母的亲兄弟 你的事就是我的事!

看了下dev环境 xxl-job admin 控制台任务的配置,看了下任务的配置没啥毛病 每5分钟执行一次
我:东老师,你是怎么发现重复执行的
东老师:我在admin 控制台启动任务后,本地任务jobHandler执行了两次但是控制台的任务执行日志记录只有一条
我:东老师,太年轻了呀,软件开发讲究的就是一个玄学,万事不决,重启解决,一次不行,那就再来一次
东老师:我本地重启了好多次了
我:那你没考虑过重启xxl-job admin控制台的任务吗
东老师一脸无奈:我都把任务删除了重新配置handler,还是一样的结果,还是会重复两次
但是呢我发现了点奇怪的东西,当我把任务cron表达式执行频率改为1min一次之后就一切正常了,2min,3min ,5min都不行
我默默的又远离了东老师:我真的是不是0,你搞了这么多就为了暗示你是个1吗,什么只有1min才会重复执行,可能吗?你觉得我像那些会被你随随便 便欺骗的富老头吗。
东老师赶紧辩解:浪啊 一你不是我喜欢的类型 二你看你像富老头吗 你不相信我,还不相信等会儿的kfc吗


好吧,那我只好带着东老师的问题来排查下原因

1. 为什么会重复执行

2. 为什么时间间隔改为1min就不会重复执行**

开始排查

先看下任务配置

打开我的idea 切换分支 拉取分支 找到对应的jobhandler 如下图,发现配置以及代码看起来很正常,
注意 ,我说的是看起来正常,毕竟程序员写的代码,没有谁能预料到结果
在这里插入图片描述
对应的xxl-job admin 控制台任务配置如下
在这里插入图片描述
我之前没研究过xxl-job的源码 所以第一时间想的是github 看看issue 有没有类似的问题 搜了一圈下来 没有找到
只好启动项目 debug模式,把dev环境的执行器地址配置我本地IP ,开启任务执行

由于对源码不熟悉 先把断点打在任务的入口处,根据堆栈信息看看从源码的哪个地方跳转过来的 并打上对应的断点.

任务第一次执行

排查执行类 ==》JobThread

第一次启动之后的确实进行了分别两次的执行,仔细观察下执行的堆栈信息,
可以看到执行我们自定义的任务就是这个**JobThread**类
在这里插入图片描述
在这里插入图片描述


JobThread的核心逻辑

第一次执行
第二次执行
仔细对比上面两个图片,至少有两个问题
1.第一次执行进来execute()接受的param居然是个null
2.两次执行任务的堆栈信息不同

在这里插入图片描述
关键任务执行类就是JobThread,我们来研究下它的主要作用

1.循环消费 一个阻塞队列 不断的去消费队列中TriggerParam 这个参数
private LinkedBlockingQueue<TriggerParam> triggerQueue;
2.看下TriggerParam,这正是我们在admin控制台配置的参数生成的实体

在这里插入图片描述

3.核心执行逻辑是下面两个执行点
134行处,执行的条件是配置了任务超时时间,新启动了一个异步线程来执行任务,我们配置的任务不会走到这个地方
152行处,是我们当前任务执行的逻辑

在这里插入图片描述
但是啊 请注意,第一次执行的参数为空的场景并没有从这块儿执行,而是如下 98行代码处执行的
在这里插入图片描述
东老师:所以这个方法为什么会被执行
执行逻辑是在这个执行线程JobThread刚刚启动,还没有进入while循环,点击这个init()方法,看了下实现类
在这里插入图片描述
在这里插入图片描述

第一个问题的结论

东老师写了个父类的同名方法init()用于本地测试,这个init()方法会在任务执行线程JobThread启动的时候执行一次,执行传参是"",所以第一次任务执行的时候拿不动执行参数☹☹☹

东老师,你是真该死啊,咱测试代码就不能删除掉吗,还有这命名太随意了吧
东老师无视我:那为什么1min不重复执行
我很生气:我说我杀人不眨眼,你问我眼睛干不干,东东,你玩我?
东老师打开刚收到的kfc外卖,没错,他拿起了一块上校鸡块,塞进了我的嘴巴
确实很好吃。
呐,东老师,那就再来看下我们开头提出的两个问题

  1. 为什么会重复执行
  2. 为什么时间间隔改为1min就不会重复执行
第一个问题已经解决,那么为什么频率1min就不重复执行呢。

我们从前面第一次执行和第二次执行的堆栈信息可以看出,
第一次执行是JobThread刚刚启动的时候,是异常逻辑
第二次执行是while循环不断消费队列中的任务,是正常执行逻辑
那么 可以猜测下1min不重复执行说明 没有第一次的执行,也就是线程没有刚刚启动,还一直处于while循环中,引出来以下的问题
1.JobThread线程什么时候启动
2.JobThread线程什么时候停止也就是while循环什么时候终止

通过第一次执行的堆栈信息,可以定位到JobThread的启动时机,就是下图中的ExecutorBizImpl 的run方法中
在这里插入图片描述
run()方法中,启动JobThread的时候会调用XxlJobExecutor.registJobThread()放进ConcurrentHashMap
而看到removeJobThread这个方法时,可以猜想下,
难道是在JobThread线程内while()循环1min之后调用removeJobThread来移除线程,从而触发了1min不重复执行的现象吗
查找调用点,果然在JobThread中有这样一个调用点
但这里并不是1min的限制,而是使用**idleTimes** 这个int变量来控制空闲执行次数,超过空闲执行30次(本地执行大概就是1min之后),线程就会销毁
在销毁之前的时间段内,任务无论启动频率是多少,都会复用这个JobThread,并不是新启动一个JobThread,所以不会重复执行。
在这里插入图片描述

在这里插入图片描述

总结

1.收到调度请求 根据当前jobId是否有已有jobThread线程存在
2.不存在则新建jobThread ,并本地ConcurrentHashMap存储
3.jobThread启动,会先执行init方法,也就是东老师用来本地测试的那个方法,然后进入while循环
4.把调度请求触发器triggerParam 放入jobThread中的队列中,while循环获取消费队列 =====正常任务的执行
5.消费队列空了之后,while空循环30次,就会停止jobThread,本地移除thread
5.1循环30次的时候,如果有任务调度进来就会继续消费 所以1min的任务一直都是同一个线程执行,不会创建新的jobthread 也不会执行init方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/641250.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

硬件学习 软件 Cadence day10 查看网表导入进度,钻孔保护等一些操作

1. 查看网表导入状态。 2. 放置元器件 之前 画板框 3.放置元器件 4.把导入的DXF 文件变成板框 1.首先导入DXF文件 2. 点击按钮 3. 鼠标点击需要 调整为板框的地方 3.1 其中包括边框 3.2 固定的钻孔 5.给钻孔打上保护&#xff08;防止布线的时候区域错误&#xff0c;在固定的时…

12. AbstractQueuedSynchronizer之AQS

12.1 前置知识 ● 公平锁和非公平锁 ○ 公平锁&#xff1a;锁被释放以后&#xff0c;先申请的线程先得到锁。性能较差一些&#xff0c;因为公平锁为了保证时间上的绝对顺序&#xff0c;上下文切换更频繁 ○ 非公平锁&#xff1a;锁被释放以后&#xff0c;后申请的线程可能会先获…

第58讲:Python编程中最难以理解的递归函数核心概念以及应用案例

文章目录 1.递归函数的概念2.递归函数的使用2.1.案例一2.1.1.需求描述2.1.2.使用常规的循环来实现2.1.3.使用递归函数实现 2.2.案例二2.2.1.需求描述2.2.2.使用常规的循环来实现2.2.3.使用递归函数实现 3.使用递归函数计算阶乘3.1.阶乘的概念3.2.使用递归函数实现阶乘的算法3.3…

分布式Profinet IO模块

PROFINET IO模块是一种用于工业自动化控制系统中的设备控制模块。它使用以太网技术&#xff0c;在现场设备和处理器/控制器之间提供快速、精确和可靠的数据交换。PROFINET IO模块通常是面向过程的&#xff0c;可以用于监测和控制工业过程中的各种设备和参数&#xff0c;如传感器…

Vue中使用editor.md(2):添加拖拽图片上传功能

0. 背景 在对editor.md简单使用后&#xff0c;希望添加图片拖拽或粘贴上传的功能。 简单使用参考&#xff1a;Vue中使用editor.md&#xff08;1&#xff09;&#xff1a;简单使用 1. 实现 1.1 添加粘贴监听 // 使用axios import axios from /api/indexfunction initPasteDra…

什么是Vue的插件?如编写自定义 Plugin?

什么是Vue的插件&#xff1f; 在Vue开发中&#xff0c;我们经常需要使用一些第三方库或功能性模块&#xff0c;Vue插件就是一种将这些库或模块集成到Vue应用中的方式。插件是Vue.js提供的一种机制&#xff0c;用于扩展Vue的功能。插件通常用于封装某些特定的功能&#xff0c;例…

【AI人工智能】 你如果要使用最强大的语言模型,你还要有最精美的浏览器标签页iTab (2)

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1…

UnityA*导航算法,通俗易懂

首先A*寻路算法分为2D算法和3D算法&#xff0c;目前它甚至不如NAVMesh算法效率高。但NAVMesh不适用于2D&#xff0c;因此2D还是要靠A*算法来进行实现。 当前就来说说2D是如何实现的。 首先2DA*算法先要将地图划分成格子分块标记成二维数组 每个格子依据x&#xff0c;y&#xf…

又一新型技术全面铺开,高精度光刻机已突破壁垒,赶超只是时间

众所周知&#xff0c;光刻机是制造高精度芯片的关键步骤。 随着科技的不断进步&#xff0c;光刻机的精度和速度也在不断提高&#xff0c;使得我们可以制造出更小更精细的芯片&#xff0c;满足了人们对于高性能电子设备的需求。 我国的光刻机技术&#xff0c;国产大飞机&#x…

【华为OD机试真题2023B卷 JAVAJS】二维伞的雨滴效应

华为OD2023(B卷)机试题库全覆盖,刷题指南点这里 二维伞的雨滴效应 知识点递归树 时间限制:1s 空间限制:256MB 限定语言:不限 题目描述: 普通的伞在二维平面世界中,左右两侧均有一条边,而两侧伞边最下面各有一个伞坠子,雨滴落到伞面,逐步流到伞坠处,会将伞坠的信息携…

UML类图(二)

相信希望&#xff0c;相信自己 上一章简单介绍了 设计模式的原则(一), 如果没有看过,请观看上一章 本文参考文章: 常见UML符号详解 UML (Unified modeling language) 统一建模语言&#xff0c;是一种用于软件系统分析和设计的语言工具&#xff0c; 它用于帮助软件开发人员进行…

强烈推荐协同办公的三个小工具

强烈推荐协同办公的三个小工具 这里给大家推荐三个可以用于协同办公的小软件工具。那么&#xff0c;什么是协同办公呢&#xff1f;直接下定义给个概念那就不好玩了&#xff0c;所以我直接推荐这么几个协同软件大家就懂了。 ONLYOFFICE办公软件 具体的软件截图我这里就不贴了&…

【Android】Frida Hook 文件读写操作

前言 在挖掘客户端漏洞的时候&#xff0c;通常会关注应用对什么文件进行了读写操作&#xff0c;当我们能控制被读的文件或观测到敏感写入的文件&#xff0c;通常可以造成一定危害。本文详细介绍了如何通过frida监控文件读写操作。 相关知识 1. 读写相关调用api 在Linux系统…

有哪些自媒体平台有播放量就会有收益?

自媒体是近年来兴起的一种新型媒体&#xff0c;指的是由个人或小团体通过互联网自行发布内容&#xff0c;通过社交媒体等渠道传播和推广的媒体形态。自媒体平台的出现&#xff0c;让更多人能够自由发表意见和观点&#xff0c;实现了信息的自由传播。同时&#xff0c;随着互联网…

跨平台.NET应用UI组件DevExpress XAF v22.2亮点 - 支持.NET 7

DevExpress XAF是一款强大的现代应用程序框架&#xff0c;允许同时开发ASP.NET和WinForms。DevExpress XAF采用模块化设计&#xff0c;开发人员可以选择内建模块&#xff0c;也可以自行创建&#xff0c;从而以更快的速度和比开发人员当前更强有力的方式创建应用程序。 在新版中…

数据结构——二叉树基础结构篇(C语言)

引言 现在是北京时间2023年6月13日9点11分。从决定要开始减脂之后&#xff0c;饥饿总是伴随着我。一觉起来肚子咕咕叫&#xff0c;我还是想先把文章发了再吃第一餐。燕麦加蛋白粉几乎伴随了我大学的第一年早饭。昨天练了一个小时背&#xff0c;练背后还做了45分钟有氧。空腹训…

BeautifulPrompt:PAI推出自研Prompt美化器,赋能AIGC一键出美图

作者&#xff1a;曹庭锋、汪诚愚、吴梓恒、黄俊 背景 Stable Diffusion&#xff08;SD&#xff09;是一种流行的AI生成内容&#xff08;AI Generated Content&#xff0c;AIGC&#xff09;模型&#xff0c;能在文字输入的基础上生成各种风格多样的图像。在目前的AIGC方向&…

十五周算法训练营——普通动态规划(上)

今天是十五周算法训练营的第十一周&#xff0c;主要讲普通动态规划&#xff08;上&#xff09;专题。&#xff08;欢迎加入十五周算法训练营&#xff0c;与小伙伴一起卷算法&#xff09; 斐波那契数 斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那…

设计模式——适配器模式

1.定义 将一个类的接口转换成客户所希望的另一个接口&#xff0c;Adapter模式使得那些原本因为接口不兼容而不能一起工作的那些类可以一起工作。 2.使用场景 一般来说&#xff0c;适配器模式可以看作一种“补偿模式”&#xff0c;用来补救设计上的缺陷。应用这种模式算是“无…

驱动开发:内核LoadLibrary实现DLL注入

远程线程注入是最常用的一种注入技术&#xff0c;在应用层注入是通过CreateRemoteThread这个函数实现的&#xff0c;该函数通过创建线程并调用 LoadLibrary 动态载入指定的DLL来实现注入&#xff0c;而在内核层同样存在一个类似的内核函数RtlCreateUserThread&#xff0c;但需要…