109 项目整合 spring-quartz 启动自动执行定时任务

前言

项目中使用了 quartz 来支持定时任务的相关基础支撑, 但是 最近添加了一个 资源消耗比较高的定时任务, 发布到测试环境之后, 发现服务突然 起不起来了[资源比较有限] 

然后 查看了一下日志, 这个定时任务怎么在执行?, 不是 配置的是 凌晨两点么, 然后 仔细一看 几乎配置的 七八个定时任务都跑了一次, 只是 可能其他的任务开销比较小, 平时没有怎么注意 

呵呵 然后 这里就是关注这个问题, 项目启动之后 所有的定时任务 自动跑了一次 

然后 在调试的过程中会发现 qrtz_triggers 会进行 多次的更新, 这些更新或许会是本文的一些核心收货之一 

备注 : 一下测试任务为1小时执行一次, 以下截图中的 fireTime 不为整点的均视为当前时间[多次调试]

 

 

定时任务的 Executor 启动执行

从这里可以看到 trigger 的 previousFireTime 是项目启动的时间, nextFireTime 是基于 previousFireTime 以及 cron 计算的下一次需要执行的时间 

这里的 previousFireTime 指的就是当前这一次定时任务的触发, 那么 这个时间 是怎么来的呢? 

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTEwMzkzMzI=,size_16,color_FFFFFF,t_70

顺便查询一下 该任务对应的数据库的记录, 是和 业务代码中获取的配置是保持一致的, 那么是哪里的代码 修改的 qrtz_triggers 呢?, 这里或许会找到一些线索 

20201226105545226.png

 

 

更新 qrtz_trigger 的 fire_time 的地方

找了一下 postgres 的日志, 呵呵 发现更新 qrtz_trigger 的 sql 大致如下, 将 nextFireTime 更新为 null, previousFireTime 更新为了 当时时间 

2020-12-21 03:40:36.663 TIME,"postgres","dcams",2724,"172.18.0.1:39966",5fe017db.aa4,7,"UPDATE",2020-12-21 03:34:51 TIME,7/1626,1159546,LOG,00000,"execute <unnamed>: UPDATE QRTZ_TRIGGERS SET JOB_NAME = $1, JOB_GROUP = $2, DESCRIPTION = $3, NEXT_FIRE_TIME = $4, PREV_FIRE_TIME = $5, TRIGGER_STATE = $6, TRIGGER_TYPE = $7, START_TIME = $8, END_TIME = $9, CALENDAR_NAME = $10, MISFIRE_INSTR = $11, PRIORITY = $12 WHERE SCHED_NAME = ''quartzScheduler'' AND TRIGGER_NAME = $13 AND TRIGGER_GROUP = $14","parameters: $1 = ''HOME_OVERVIEW'', $2 = ''DEFAULT'', $3 = NULL, $4 = ''1608522036590'', $5 = ''-1'', $6 = ''WAITING'', $7 = ''CRON'', $8 = ''1600052000000'', $9 = ''0'', $10 = NULL, $11 = ''0'', $12 = ''5'', $13 = ''HOME_OVERVIEW'', $14 = ''DEFAULT''",,,,,,,,"PostgreSQL JDBC Driver"
2020-12-21 03:40:36.667 TIME,"postgres","dcams",2724,"172.18.0.1:39966",5fe017db.aa4,8,"UPDATE",2020-12-21 03:34:51 TIME,7/1626,1159546,LOG,00000,"execute <unnamed>: UPDATE QRTZ_CRON_TRIGGERS SET CRON_EXPRESSION = $1, TIME_ZONE_ID = $2 WHERE SCHED_NAME = ''quartzScheduler'' AND TRIGGER_NAME = $3 AND TRIGGER_GROUP = $4","parameters: $1 = ''0 0 0/1 * * ?'', $2 = ''Asia/Shanghai'', $3 = ''HOME_OVERVIEW'', $4 = ''DEFAULT''",,,,,,,,"PostgreSQL JDBC Driver"

 

根据上面的 update sql, 我们找一下 其在代码中的位置 

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTEwMzkzMzI=,size_16,color_FFFFFF,t_70

 

然后定位一下使用的地方 打上断点, 呵呵 果然就来了 

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTEwMzkzMzI=,size_16,color_FFFFFF,t_70

 

经过调试发现, trigger 的 nextFireTime 更新为当前时间是在 trig. updateAfterMisfire, 呵呵 这个我们后面再看 

我们先看一些 能够推进事情继续往下走的东西 

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTEwMzkzMzI=,size_16,color_FFFFFF,t_70

 

我们来看一下 更新 trigger nextFireTime 更新为当前时间之前的一些情况, 呵呵 这里的 nextFireTime 是 2020.09.14 11:00?, 从时间上来推测 大概可以推测是根据 startTime 计算的下一次触发的时间[我们稍后会有具体的代码的体现]

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTEwMzkzMzI=,size_16,color_FFFFFF,t_70

 

顺便查询一下 该任务对应的数据库的记录, 是和 这里业务代码中获取的配置是保持一致的, 那么是哪里的代码 修改的 qrtz_triggers 呢?, 这里或许会找到一些线索 

下一个坑先挖在这里了[上一次更新 qrtz_trigger 的 fire_time 的地方], 我们接下来先填现在的这个坑 

20201226111621661.png

 

看一下 CronTrigger 对于 misfire 的任务的处理, 有几种策略, 我们这里的情况是 默认的 SMART_POLICY, 这里转换为了 立即触发一次 

1. 忽略 就直接退出了, fireTime 相关不变 

2. doNothing 是啥都不做, 但是根据当前时间重新计算一下 下一次触发的时间 

3. 立即触发一次, 是更新下一次触发时间为当前时间 

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTEwMzkzMzI=,size_16,color_FFFFFF,t_70

 

这里可以看到 nextFireTime 更新成了当前时间, 但是在上一个阶段我们看到的结果是 previousFireTime 是当前时间, nextFireTime 是根据当前时间计算的下一个触发时间点, 是怎么回事呢 ?

上面吧 nextFireTime 更新成当前时间, 接着会触发一次当前任务的执行, 下面的地方 会更新 qrtz_trigger, switch 一下, trigger.triggered(cal) 会根据当前这次触发的时间计算下一次的触发时间, 并将 previousFireTime 更新为这一次的触发时间 

下面的 qrtz_trigger 的更新 还是走的是上面的更新的方法, 相同的 sql 

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTEwMzkzMzI=,size_16,color_FFFFFF,t_70

 

 

上一次更新 qrtz_trigger 的 fire_time 的地方

假设我项目上一次关闭的时候 qrtz_trigger HOME_OVERVIEW 的 nextFireTime 和 previousFireTime 分别为 2020.12.26 15:00 和 2020.12.26 16:00

那么 qrtz_trigger 是怎么被更新成 nextFireTime 是 2020.09.14 11:00 的呢? spring-quartz 是怎么做到 每一次重启都会重新执行一次 定时任务的呢 ? 

因为 如果我是在 2020.12.26 15:20 重启, 那么按照上面的配置, 我们的这个任务 应该是不属于 misfire 的情况, 应该是不会走 misfire 的处理[上面的 fire_once_now] 

但是这里又会有一个疑问, 当时是在我的立场上面, 既然 qrtz_trigger 在上面的 "更新 qrtz_trigger 的 fire_time 的地方" 之前就被更新了?, 那么我上面的断点为什么第一次进来的时候 nextFireTime 为当前时间呢?, 不应该是为 2020.09.14 11:00 么?

1. 说明还有这个sql还有其他地方使用到[我的立场上面我是看过, 打过断点的, 我是可以否定]

2. 说明还有其他的 sql 会更新 qrtz_trigger, 呵呵 继续 track 一下 sql 

还是在我上面的 "更新 qrtz_trigger 的 fire_time 的地方" 断点上, 然后找一下 postgres 日志, 呵呵 找一下 这部分将 qrtz_trigger 的 nextFireTime 更新成 2020.09.14 11:00 的地方, 呵呵 找到了, 原来是先删除了, 然后 在添加进去的阿 

22020-12-21 05:48:02.294 TIME,"postgres","dcams",2925,"172.18.0.1:40038",5fe036fc.b6d,35,"DELETE",2020-12-21 05:47:40 TIME,7/1668,1159558,LOG,00000,"execute S_23: DELETE FROM QRTZ_TRIGGERS WHERE SCHED_NAME = ''quartzScheduler'' AND TRIGGER_NAME = $1 AND TRIGGER_GROUP = $2","parameters: $1 = ''HOME_OVERVIEW'', $2 = ''DEFAULT''",,,,,,,,"PostgreSQL JDBC Driver"
2020-12-21 05:48:02.325 TIME,"postgres","dcams",2925,"172.18.0.1:40038",5fe036fc.b6d,36,"INSERT",2020-12-21 05:47:40 TIME,7/1668,1159558,LOG,00000,"execute S_25: INSERT INTO QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP, JOB_NAME, JOB_GROUP, DESCRIPTION, NEXT_FIRE_TIME, PREV_FIRE_TIME, TRIGGER_STATE, TRIGGER_TYPE, START_TIME, END_TIME, CALENDAR_NAME, MISFIRE_INSTR, JOB_DATA, PRIORITY)  VALUES(''quartzScheduler'', $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)","parameters: $1 = ''HOME_OVERVIEW'', $2 = ''DEFAULT'', $3 = ''HOME_OVERVIEW'', $4 = ''DEFAULT'', $5 = NULL, $6 = ''1600052400000'', $7 = ''-1'', $8 = ''WAITING'', $9 = ''CRON'', $10 = ''1600052000000'', $11 = ''0'', $12 = NULL, $13 = ''0'', $14 = ''\x'', $15 = ''5''",,,,,,,,"PostgreSQL JDBC Driver"

 

然后我们在 INSERT_TRIGGER 使用的地方来上一个断点, 呵呵 看到了 nextFireTime 计算为 2020.09.14 11:00, 并且即将插入到数据库的场景了 

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTEwMzkzMzI=,size_16,color_FFFFFF,t_70

 

我们看一下具体的更新 trigger 的 fireTime 的地方, 呵呵 在如下代码 trig.computeFirstFireTime(cal) 

可以看到的是 newTrigger 是给 Scheduler 这边传入的 trigger, oldTrigger 看这里的情况应该是直接从数据库又查询了一次, 得到的 trigger 的状态 

可以看到大致的情况是 项目启动的时候会将各个任务添加到 Scheduler, 然后这里会根据各个任务的 startTime 重新计算 nextFireTime, 然后 替换掉数据库中已有的 qrtz_trigger[启动项目之前已经存在的 qrtz_trigger], 然后后面的 misfire 补偿检测到了 这个任务属于 misfire 的任务, 然后根据策略进行处理, 策略为 SMART_POLICY, 实际的实现中等价于 FIRE_ONCE_NOW, 立即触发了一次 

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTEwMzkzMzI=,size_16,color_FFFFFF,t_70

 

computeFirstFireTime 的方式, 呵呵 根据 startTime 进行的计算 

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTEwMzkzMzI=,size_16,color_FFFFFF,t_70

 

查看一下当前的 qrtz_trigger 的状态 

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTEwMzkzMzI=,size_16,color_FFFFFF,t_70

所以, 到这里 你明白了这一系列的 qrtz_trigger 的转换了么? 

 

 

解决问题

更新一下外部传入给 Scheduler. rescheduleJob(TriggerKey triggerKey, Trigger newTrigger) 传入的 newTrigger 的 misfireInstruction, 更新为 doNothing 即可 

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTEwMzkzMzI=,size_16,color_FFFFFF,t_70

 

 

完 

 

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

跳槽多次未成功,问题源自何处?

众所周知&#xff0c;2023年市场很难&#xff01;看着企业们纷纷裁员&#xff0c;甚至连内推这个后门都走不通&#xff01;哪怕有面试&#xff0c;都是屡屡碰壁&#xff0c;你想清楚问题出在哪了吗&#xff1f;&#x1f62d;“求职不得&#xff0c;夜不能寐&#xff1b;三更半夜…

免费升级https的方式(含教学)

背景&#xff1a;随着现在全民网络安全意识的日益提升&#xff0c;各个网站实现的https数量也随之提升&#xff0c;那么如何将原本网站的http访问方式升级为https呢&#xff1f;下面均为干货内容。 目录 http访问和https访问的区别&#xff1a; 实现https后有哪些好处&#x…

两个现货白银理财产品投资技术分析方法

现货白银是投资市场中比较受欢迎的理财产品。要投资现货白银&#xff0c;我们需要具备一定的金融投资经验。下面我们就来讨论一下&#xff0c;在现货白银这个理财产品的投资过程中&#xff0c;常常用到的一些技术分析方法。 宏观的趋势分析法。在现货白银理财产品投资中&#x…

助农抢农时,千耘导航保春耕

助农抢农时&#xff0c;千耘导航保春耕 在农业生产中&#xff0c;农机的作用不可忽视。随着人们生活水平的提高和科技的进步&#xff0c;对于农机的需求也越来越大。而千耘农机导航作为农机自动驾驶领域独具优势的一款设备&#xff0c;正以火爆的势头成为众多农户的首选。 在春…

C 结构体链表的一点想法

去年写的 白天和同事在聊一个东西&#xff0c;关于 c 里面链表的使用&#xff0c;通常是用一个 list 作为结构体的成员&#xff0c;然后通过 list 把结构体串起来&#xff0c;就像串糖葫芦一样。 而我发现项目中有一个结构体有三个类似 list 这样的成员&#xff0c;一个成员是…

20240318uniapp怎么引用组件

在script中增加 import index from "/pages/index/index.vue" 把index直接整个作为一个组件引入 然后注册组件 在export default中增加 components: {index:index }, 注册了index组件&#xff0c;内容为import的index 然后就可以在template里使用 <index&…

3/20作业

1> 创建一个工人信息库&#xff0c;包含工号&#xff08;主键&#xff09;、姓名、年龄、薪资。 2> 添加三条工人信息&#xff08;可以完整信息&#xff0c;也可以非完整信息&#xff09; 3> 修改某一个工人的薪资&#xff08;确定的一个&#xff09; 4> 展示出工资…

AL379芯片和AL383芯片是一款DC-DC升压芯片IC

首先&#xff0c;我们来了解HU6283芯片5V升压12V芯片的工作原理。这种芯片通常采用开关电源技术&#xff0c;通过高频开关控制&#xff0c;将5V的输入电压转换为12V的输出电压。开关电源技术具有高效、稳定、体积小等优点&#xff0c;因此在电子设备中得到了广泛应用。5V升压12…

C语言基础知识点(十八)联合、

【C语言】联合体-共用体 &#xff08;union&#xff09; 详解-阿里云开发者社区 (aliyun.com) 联合 在C语言中是一种数据类型&#xff0c;能在同一个内存空间中存储不同的数据类型&#xff08;不是同时储存&#xff09;。 典型用法&#xff1a;设计一种表以存储及无规律、实…

(C语言) print输出函数系列介绍

(C语言) print输出函数系列介绍 文章目录 (C语言) print输出函数系列介绍前言输出系列函数&#x1f5a8;️printf&#x1f5a8;️sprintf & snprintf&#x1f5a8;️fprintf&#x1f5a8;️vprintf&#x1f5a8;️dprintf&#x1f5a8;️puts&#x1f5a8;️fputs&#x1f…

Java开发---上海得帆(一面)

面试感受 这是我的第一次面试&#xff0c;我感觉我这次面试的很差&#xff0c;很糟糕&#xff0c;十分的糟糕&#xff0c;万分的糟糕。第一次面试&#xff0c;面试了半个小时。我去真的好紧张&#xff0c;脑子里一篇空白。脑子空白还不是最惨的&#xff0c;最惨的是那个八股文…

【C语言进阶篇】自定义类型:联合体和枚举

【C语言进阶篇】自定义结构体类型&#xff1a;联合体和枚举 &#x1f308;个人主页&#xff1a;开敲 &#x1f525;所属专栏&#xff1a;C语言 &#x1f33c;文章目录&#x1f33c; 1. 联合体 1.1 联合体类型的声明 1.2 联合体的特点 1.3 联合体大小的计算 2. 枚举 2.1 枚举…

动态内存经典笔试题分析及柔性数组

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…

链式二叉树

前言 本章将重点讲解链式二叉树的四种遍历方式。 一、链式二叉树 1、引入链式二叉树 我们知道完全二叉树可以使用堆存储&#xff0c;那非完全二叉树&#xff1f; 非完全二叉树不适合用堆来存储&#xff0c;因为浪费空间&#xff0c;所以非完全二叉树使用链式存储。 2、链式二…

做独立站烧不烧钱?真做起来的话要投入多少成本?

建立一个独立网站需要花钱吗&#xff1f; 实际做起来要花多少钱&#xff1f; 这是一种灵魂的拷问&#xff0c;也是大多数想进入这个行业或者刚刚起步的人都在思考或者思考的问题。 对于这样的问题&#xff0c;没有人能够给出确切的数字&#xff0c;甚至是确定的答案。 至于为什…

python基础——对序列的通用操作【+和*、in、切片操作、separator.join(iterable)】

&#x1f4dd;前言&#xff1a; 我们已经学习了python数据容器中的列表&#xff0c;元组以及字符串。而他们都属于序列 &#xff08;序列是指&#xff1a;内容连续&#xff0c;有序&#xff0c;可以用下标索引访问的数据容器&#xff09; 在之前已经介绍了不少操作方法&#xf…

NVIDIA 推出地球-2云平台,使用AI超级计算机的模拟技术,预测整个地球的气候变化

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Sui技术帮助Studio Mirai成功实现创意愿景

Brian和Ben Li兄弟对艺术充满热情&#xff0c;通过共同创立的研发工作室Studio Mirai&#xff0c;他们正在探索Web3技术与创意产业的交集。 Studio Mirai的第一个头像类项目&#xff08;profile picture&#xff0c;PFP&#xff09;Tamashi存在于Nozomi World中&#xff0c;这…

教育内卷化:焦虑下的竞争与反思

教育内卷化&#xff1a;焦虑下的竞争与反思 一、教育内卷化的现象解读 教育内卷化&#xff0c;作为当前社会的热点话题&#xff0c;体现了教育资源竞争日趋激烈的现状。这一现象在中小学阶段尤为明显&#xff0c;家长们为了让孩子进入优质学校&#xff0c;不惜花费巨资购买学…

【SpringCloud】Consul中数据持久化配置并注册为Windows服务

Consul用起来两个比较麻烦的地方: 一是每次都需要执行打开命令行执行 consul agent -dev 命令来启动Consul服务,而且不能关掉命令行.另外一点就是在Consul中设置的数据,每次重启之后就没了. 就很烦.因此为大家带来解决上述问题的方法 首先要在官网下载Consul安装包的解压目录下…