一次XxlJob调度任务重复执行的问题排查 | 您所在的位置:网站首页 › 重复的一天又结束了 › 一次XxlJob调度任务重复执行的问题排查 |
目录
东老师的问题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 如下图,发现配置以及代码看起来很正常, 注意 ,我说的是看起来正常,毕竟程序员写的代码,没有谁能预料到结果 由于对源码不熟悉 先把断点打在任务的入口处,根据堆栈信息看看从源码的哪个地方跳转过来的 并打上对应的断点. 任务第一次执行 排查执行类 ==》JobThread第一次启动之后的确实进行了分别两次的执行,仔细观察下执行的堆栈信息, 可以看到执行我们自定义的任务就是这个**JobThread**类 第一次执行 第二次执行 仔细对比上面两个图片,至少有两个问题 1.第一次执行进来execute()接受的param居然是个null 2.两次执行任务的堆栈信息不同
东老师写了个父类的同名方法init()用于本地测试,这个init()方法会在任务执行线程JobThread启动的时候执行一次,执行传参是"",所以第一次任务执行的时候拿不动执行参数☹☹☹ 东老师,你是真该死啊,咱测试代码就不能删除掉吗,还有这命名太随意了吧 东老师无视我:那为什么1min不重复执行 我很生气:我说我杀人不眨眼,你问我眼睛干不干,东东,你玩我? 东老师打开刚收到的kfc外卖,没错,他拿起了一块上校鸡块,塞进了我的嘴巴 确实很好吃。 呐,东老师,那就再来看下我们开头提出的两个问题 为什么会重复执行为什么时间间隔改为1min就不会重复执行 第一个问题已经解决,那么为什么频率1min就不重复执行呢。我们从前面第一次执行和第二次执行的堆栈信息可以看出, 第一次执行是JobThread刚刚启动的时候,是异常逻辑 第二次执行是while循环不断消费队列中的任务,是正常执行逻辑 那么 可以猜测下1min不重复执行说明 没有第一次的执行,也就是线程没有刚刚启动,还一直处于while循环中,引出来以下的问题 1.JobThread线程什么时候启动 2.JobThread线程什么时候停止也就是while循环什么时候终止 通过第一次执行的堆栈信息,可以定位到JobThread的启动时机,就是下图中的ExecutorBizImpl 的run方法中 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方法 |
CopyRight 2018-2019 实验室设备网 版权所有 |