原理篇-- 定时任务xxl-job-服务端(admin)项目启动过程--JobFailMonitorHelper初始化 (5)

文章目录

  • 前言
  • 一、JobFailMonitorHelper作用:
  • 二、JobFailMonitorHelper源码内容:
    • 2.1 start() 初始化
      • 2.1.1 任务失败重试:
      • 2.1.2 任务失败告警信息发送:
        • 2.1.2.1 JobAlarmer 告警类:
        • 2.1.2.2 alarm 告警信息发送:
    • 2.2 toStop() 终止线程释放资源:
  • 总结


前言

本文对JobFailMonitorHelper的工作内容进行介绍。


一、JobFailMonitorHelper作用:

JobFailMonitorHelper是xxl-job-admin中的一个辅助类,用于监控任务执行失败情况并进行处理。其主要作用包括:

  1. 监控任务执行失败:JobFailMonitorHelper定时检测任务执行情况,发现任务执行失败的情况,例如任务执行超时、执行异常等。

  2. 处理任务执行失败:一旦发现任务执行失败,JobFailMonitorHelper会根据预设的处理策略来进行处理,例如重新执行任务、发送告警通知等。

  3. 统计和报表:JobFailMonitorHelper会统计任务执行失败的情况,生成报表并提供给管理员查看,以便对任务执行情况进行监控和分析。

  4. 增强系统健壮性:通过及时监控和处理任务执行失败情况,JobFailMonitorHelper能够提高系统的健壮性和可靠性,确保任务能够按时正确执行。

总的来说,JobFailMonitorHelper在xxl-job-admin中扮演着监控任务执行失败情况并进行处理的重要角色,帮助管理员及时发现和处理任务执行异常情况,提高系统的稳定性和可靠性。

二、JobFailMonitorHelper源码内容:

2.1 start() 初始化

2.1.1 任务失败重试:

// 定义log 对象
private static Logger logger = LoggerFactory.getLogger(JobFailMonitorHelper.class);
// 实例化 JobFailMonitorHelper  对象	 
private static JobFailMonitorHelper instance = new JobFailMonitorHelper();
public static JobFailMonitorHelper getInstance(){return instance;
}// ---------------------- monitor ----------------------
// 定义监控线程 monitorThread
private Thread monitorThread;
// 任务while 循环标识
private volatile boolean toStop = false;
public void start(){monitorThread = new Thread(new Runnable() {@Overridepublic void run() {// monitorwhile (!toStop) {try {// 获取最近的 1000 条任务执行失败的任务id 集合/*** SELECT id FROM `xxl_job_log`WHERE !((trigger_code in (0, 200) and handle_code = 0)OR(handle_code = 200))AND `alarm_status` = 0ORDER BY id ASCLIMIT #{pagesize}**/List<Long> failLogIds = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().findFailJobLogIds(1000);if (failLogIds!=null && !failLogIds.isEmpty()) {for (long failLogId: failLogIds) {// 遍历失败的任务id 集合// lock log 乐观锁占用/*** UPDATE xxl_job_logSET`alarm_status` = #{newAlarmStatus}WHERE `id`= #{logId} AND `alarm_status` = #{oldAlarmStatus}**/int lockRet = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateAlarmStatus(failLogId, 0, -1);if (lockRet < 1) {// 锁抢占失败,绩效下个任务遍历continue;}// 获取任务执行的log 对象/*** 	SELECT <include refid="Base_Column_List" />FROM xxl_job_log AS tWHERE t.id = #{id}**/XxlJobLog log = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().load(failLogId);// 获取 任务的详情/*** 	SELECT <include refid="Base_Column_List" />FROM xxl_job_info AS tWHERE t.id = #{id}**/XxlJobInfo info = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().loadById(log.getJobId());// 1、fail retry monitor  判断任务的失败重试次数if (log.getExecutorFailRetryCount() > 0) {// 失败重试次数大于0 触发任务重试,每次重试都将任务的 重试次数-1/*** 任务的触发执行细节可以参考 文章:* 原理篇-- 定时任务xxl-job-服务端(admin)项目启动过程--JobTriggerPoolHelper 初始化 (3)* 连接: https://blog.csdn.net/l123lgx/article/details/136349951**/JobTriggerPoolHelper.trigger(log.getJobId(), TriggerTypeEnum.RETRY, (log.getExecutorFailRetryCount()-1), log.getExecutorShardingParam(), log.getExecutorParam(), null);String retryMsg = "<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_type_retry") +"<<<<<<<<<<< </span><br>";// 追加任务重试的执行结果log.setTriggerMsg(log.getTriggerMsg() + retryMsg);// 更新log 对象信息XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateTriggerInfo(log);}// 2、fail alarm monitor 失败告警信息发送int newAlarmStatus = 0;		// 告警状态:0-默认、-1=锁定状态、1-无需告警、2-告警成功、3-告警失败if (info != null) {// 执行告警业务boolean alarmResult = XxlJobAdminConfig.getAdminConfig().getJobAlarmer().alarm(info, log);					// 标识告警的结果newAlarmStatus = alarmResult?2:3;} else {// 无需告警newAlarmStatus = 1;}// 更新log 对象的告警信息/*** UPDATE xxl_job_logSET`alarm_status` = #{newAlarmStatus}WHERE `id`= #{logId} AND `alarm_status` = #{oldAlarmStatus}**/XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateAlarmStatus(failLogId, -1, newAlarmStatus);}}} catch (Exception e) {if (!toStop) {logger.error(">>>>>>>>>>> xxl-job, job fail monitor thread error:{}", e);}}try {TimeUnit.SECONDS.sleep(10);} catch (Exception e) {if (!toStop) {logger.error(e.getMessage(), e);}}}logger.info(">>>>>>>>>>> xxl-job, job fail monitor thread stop");}});// 设置 monitorThread线程 守护线程,名字,运行monitorThread.setDaemon(true);monitorThread.setName("xxl-job, admin JobFailMonitorHelper");monitorThread.start();
}

2.1.2 任务失败告警信息发送:

XxlJobAdminConfig.getAdminConfig().getJobAlarmer().alarm(info, log) 获取所有实现了JobAlarm 接口的bean 遍历调用 doAlarm 方法;

2.1.2.1 JobAlarmer 告警类:

1)JobAlarmer 的初始化:

//  @Component 标识被spring 识别 构建 JobAlarmer 的bean 对象并放入到单例池中
@Component
public class JobAlarmer implements ApplicationContextAware, InitializingBean {private static Logger logger = LoggerFactory.getLogger(JobAlarmer.class);private ApplicationContext applicationContext;private List<JobAlarm> jobAlarmList;// 实现ApplicationContextAware 在容器创建后可以执行 setApplicationContext 注入容器的上下文@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}// 实现InitializingBean  在JobAlarmer 的bean 属性注入后,调用afterPropertiesSet 完成初始化@Overridepublic void afterPropertiesSet() throws Exception {// 从当前项目容器中获取到 JobAlarm类型的所有bean对象Map<String, JobAlarm> serviceBeanMap = applicationContext.getBeansOfType(JobAlarm.class);if (serviceBeanMap != null && serviceBeanMap.size() > 0) {// 将bean 对象填充到 jobAlarmList 集合中jobAlarmList = new ArrayList<JobAlarm>(serviceBeanMap.values());}}
}

2) JobAlarm 告警接口类:

public interface JobAlarm {/*** job alarm** @param info* @param jobLog* @return*/public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog);}

3)JobAlarm 的实现类 EmailJobAlarm:
目前服务端实现告警的类只有EmailJobAlarm 通过邮件告警,如果要扩展可以仿照EmailJobAlarm 实现 JobAlarm 重写 doAlarm 方法即可;

/*** job alarm by email** @author xuxueli 2020-01-19*/
@Component
public class EmailJobAlarm implements JobAlarm {private static Logger logger = LoggerFactory.getLogger(EmailJobAlarm.class);/*** fail alarm 执行告警逻辑** @param jobLog*/@Overridepublic boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog){boolean alarmResult = true;// send monitor emailif (info!=null && info.getAlarmEmail()!=null && info.getAlarmEmail().trim().length()>0) {// 告警邮件地址不为空// alarmContentString alarmContent = "Alarm Job LogId=" + jobLog.getId();if (jobLog.getTriggerCode() != ReturnT.SUCCESS_CODE) {alarmContent += "<br>TriggerMsg=<br>" + jobLog.getTriggerMsg();}if (jobLog.getHandleCode()>0 && jobLog.getHandleCode() != ReturnT.SUCCESS_CODE) {alarmContent += "<br>HandleCode=" + jobLog.getHandleMsg();}// email infoXxlJobGroup group = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().load(Integer.valueOf(info.getJobGroup()));String personal = I18nUtil.getString("admin_name_full");String title = I18nUtil.getString("jobconf_monitor");String content = MessageFormat.format(loadEmailJobAlarmTemplate(),group!=null?group.getTitle():"null",info.getId(),info.getJobDesc(),alarmContent);Set<String> emailSet = new HashSet<String>(Arrays.asList(info.getAlarmEmail().split(",")));// 遍历邮件地址 发送信息for (String email: emailSet) {// make mailtry {MimeMessage mimeMessage = XxlJobAdminConfig.getAdminConfig().getMailSender().createMimeMessage();MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);helper.setFrom(XxlJobAdminConfig.getAdminConfig().getEmailFrom(), personal);helper.setTo(email);helper.setSubject(title);helper.setText(content, true);XxlJobAdminConfig.getAdminConfig().getMailSender().send(mimeMessage);} catch (Exception e) {logger.error(">>>>>>>>>>> xxl-job, job fail alarm email send error, JobLogId:{}", jobLog.getId(), e);alarmResult = false;}}}return alarmResult;}/*** load email job alarm template** @return*/private static final String loadEmailJobAlarmTemplate(){String mailBodyTemplate = "<h5>" + I18nUtil.getString("jobconf_monitor_detail") + ":</span>" +"<table border=\"1\" cellpadding=\"3\" style=\"border-collapse:collapse; width:80%;\" >\n" +"   <thead style=\"font-weight: bold;color: #ffffff;background-color: #ff8c00;\" >" +"      <tr>\n" +"         <td width=\"20%\" >"+ I18nUtil.getString("jobinfo_field_jobgroup") +"</td>\n" +"         <td width=\"10%\" >"+ I18nUtil.getString("jobinfo_field_id") +"</td>\n" +"         <td width=\"20%\" >"+ I18nUtil.getString("jobinfo_field_jobdesc") +"</td>\n" +"         <td width=\"10%\" >"+ I18nUtil.getString("jobconf_monitor_alarm_title") +"</td>\n" +"         <td width=\"40%\" >"+ I18nUtil.getString("jobconf_monitor_alarm_content") +"</td>\n" +"      </tr>\n" +"   </thead>\n" +"   <tbody>\n" +"      <tr>\n" +"         <td>{0}</td>\n" +"         <td>{1}</td>\n" +"         <td>{2}</td>\n" +"         <td>"+ I18nUtil.getString("jobconf_monitor_alarm_type") +"</td>\n" +"         <td>{3}</td>\n" +"      </tr>\n" +"   </tbody>\n" +"</table>";return mailBodyTemplate;}}
2.1.2.2 alarm 告警信息发送:

获取所有实现了JobAlarm 接口的bean 遍历调用 doAlarm 方法;

public boolean alarm(XxlJobInfo info, XxlJobLog jobLog) {// List<JobAlarm> jobAlarmList 遍历 所有实现了JobAlarm 接口的bean boolean result = false;if (jobAlarmList!=null && jobAlarmList.size()>0) {result = true;  // success means all-successfor (JobAlarm alarm: jobAlarmList) {boolean resultItem = false;try {resultItem = alarm.doAlarm(info, jobLog);} catch (Exception e) {logger.error(e.getMessage(), e);}if (!resultItem) {result = false;}}}返回告警结果return result;}

2.2 toStop() 终止线程释放资源:

public void toStop(){toStop = true;// interrupt and waitmonitorThread.interrupt();try {monitorThread.join();} catch (InterruptedException e) {logger.error(e.getMessage(), e);}
}

总结

本文对 JobFailMonitorHelper的工作内容进行介绍。

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

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

相关文章

数据可视化原理-腾讯-3D网格热力图

在做数据分析类的产品功能设计时&#xff0c;经常用到可视化方式&#xff0c;挖掘数据价值&#xff0c;表达数据的内在规律与特征展示给客户。 可是作为一个产品经理&#xff0c;&#xff08;1&#xff09;如果不能够掌握各类可视化图形的含义&#xff0c;就不知道哪类数据该用…

壁炉火焰温和而宁静,警惕火焰凶猛的潜在危害

在寒冷的冬夜&#xff0c;壁炉散发的温暖和闪烁的火焰成为家庭的心灵港湾。然而&#xff0c;我们在享受壁炉带来的温馨时&#xff0c;有时候也要关注火焰的凶猛度&#xff0c;因为它可能引发一系列潜在危害。 首先&#xff0c;壁炉的火焰过于凶猛可能导致空气质量下降。当火焰过…

从零开始手写RPC框架(4)

这一节主要讲述网络传输模块的代码&#xff0c;并且几乎每一行代码都加上了我个人理解的注释&#xff0c;同时也讲述了其中一些以前没见过的函数&#xff0c;和大致的底层运行逻辑。 目录 网络传输实体类网络传输实现基于Socket实现网络传输基于Netty实现网络传输客户端服务端 …

【JavaEE进阶】 Linux常用命令

文章目录 &#x1f343;前言&#x1f334;ls 与 pwd&#x1f6a9;ls&#x1f6a9;pwd &#x1f38d;cd&#x1f6a9;认识Linux目录结构 &#x1f340;touch与cat&#x1f6a9;touch&#x1f6a9;cat &#x1f332;mkdir与rm&#x1f6a9;mkdir&#x1f6a9;rm &#x1f384;cp与…

GD库没有安装FreeType 支持Call to undefined function App\Services\imagettfbbox()

GD库是一个功能强大的图像处理库&#xff0c;广泛用于生成和处理图像。然而&#xff0c;默认情况下&#xff0c;GD库不包含FreeType扩展&#xff0c;该扩展用于处理字体和文本。如果您需要在GD库中使用更多的字体和文本效果&#xff0c;您可以按照以下步骤安装和启用FreeType扩…

十五、单词造句

描述 GG Bond在和妹妹做一个游戏&#xff0c;GG Bond给定了妹妹一些单词字符串&#xff0c;他想让妹妹把这些单词拼接成以空格间隔开的句子&#xff0c;很可惜妹妹Python没有学好&#xff0c;你能使用join函数帮帮她吗&#xff1f; 输入描述&#xff1a; 多行输入多个字符串…

Java基础 - 7 - 常用API(二)

API&#xff08;全称 Application Programming Interface&#xff1a;应用程序编程接口&#xff09; API就是Java帮我们已经写好的一些程序&#xff0c;如类、方法等&#xff0c;可以直接拿过来用 JDK8 API文档&#xff1a;Java Platform SE 8 一. Object Object类的作用 Ob…

mybatis多数据源切换

1.前提 项目中有可能需要去其他的数据库取其他的表的信息 2.思路 2.1 直接使用原生jdbc&#xff08;不推荐&#xff09; 2.2 不使用我们全局配置的mybatis&#xff0c;对指定文件夹下使用我们指定的Session 3.解决办法 指定该配置的范围 package com.maycur.openapi.dao.my…

『Linux从入门到精通』第 ㉓ 期 - 管道

文章目录 &#x1f490;专栏导读&#x1f490;文章导读&#x1f427;进程间通信的目的&#x1f427;如何进行进程间通信&#x1f427;进程间通信的分类&#x1f427;管道&#x1f426;什么是管道&#x1f426;管道原理 &#x1f427;实例代码&#x1f427;管道的特点&#x1f4…

Protobuf学习笔记以及序列化的一些概念要点(暂放C++笔记专栏)

Protobuf学习笔记以及序列化的一些概念要点 —— 杭州 2024-03-03 文章目录 Protobuf学习笔记以及序列化的一些概念要点1.Protobuf概念2.实际测试2.1.准备一个test.proto2.2.使用 protoc 命令行工具来编译一个 Protocol Buffers 文件 test.proto3.3.创建一个main.cpp写C++代码…

mysql 事务的隔离级别

一、事务的隔离级别要解决的问题&#xff1a; 1&#xff09;脏读&#xff1a;读到了其它事务未提交的数据即脏读&#xff0c;未提交意味着数据有可能会被回滚&#xff0c;也就是最终有可能不会存储到数据库中&#xff0c;即读到了最终不一定存在存在的数据&#xff0c;即为脏读…

如何选择程序员职业赛道:挑战与机遇并存的职业探索指南

程序员如何选择职业赛道&#xff1f; 作为程序员&#xff0c;选择职业赛道是一项重要的决策&#xff0c;不仅影响你的职业发展&#xff0c;也影响着你的工作生活。本文将为你介绍如何选择程序员职业赛道&#xff0c;以及每个方向的特点、挑战和机遇&#xff0c;帮助你做出明智…

《极客时间 - 左耳听风》【文章笔记 + 个人思考】

《极客时间 - 左耳听风》 原文链接 &#xff1a;https://time.geekbang.org/column/intro/100002201?tabcatalog 备注&#xff1a;加粗部分为个人思考 01 | 程序员如何用技术变现&#xff1f;&#xff08;上&#xff09; 备注&#xff1a;加粗部分为个人思考) 01 | 程序员如何…

Window系统部署Splunk Enterprise并结合内网穿透实现远程访问本地服务

文章目录 前言1. 搭建Splunk Enterprise2. windows 安装 cpolar3. 创建Splunk Enterprise公网访问地址4. 远程访问Splunk Enterprise服务5. 固定远程地址 前言 本文主要介绍如何简单几步&#xff0c;结合cpolar内网穿透工具实现随时随地在任意浏览器&#xff0c;远程访问在本地…

【24最新版PythonPycharm安装教程】小白保姆级别安装教程

今天&#xff0c;我就来教大家一下&#xff0c;如何去安装Python&#xff01; 需要博主打包好的一键激活版Pycharm&&Python也可扫下方直接获取 ​ 1 了解Python Python是一种面向对象的解释型计算机程序设计语言&#xff0c;由荷兰人Guido van Rossum于1989年发明&…

[C++]使用纯opencv去部署yolov9的onnx模型

【介绍】 部署 YOLOv9 ONNX 模型在 OpenCV 的 C 环境中涉及一系列步骤。以下是一个简化的部署方案概述&#xff0c;以及相关的文案。 部署方案概述&#xff1a; 模型准备&#xff1a;首先&#xff0c;你需要确保你有 YOLOv9 的 ONNX 模型文件。这个文件包含了模型的结构和权…

Flutter Gradle下载失败的解决方案

Flutter Gradle可能会由于网络原因下载失败,这个时候我们可以首先下载Gradle&#xff0c;然后再进行配置。具体步骤如下&#xff1a; 第一步&#xff1a;下载对应版本的gradle 可以通过下面地址下载&#xff0c;也可以百度里面搜对应的版本 【极速下载】gradle各版本快速下载地…

【HTML】HTML基础2(一些常用标签)

目录 例子 首先是网页图标 然后是一些常用标签 插入图片 例子 <!DOCTYPE html> <html><head><link rel"icon" href"img/银河护卫队-星爵.png" type"image/x-icon"><meta charset"utf-8"><title>…

大数据的分类分级管理

一.背景 为了公司给的师带徒&#xff0c;为培训写点材料。让徒弟做事情要有章法&#xff0c;有行业视野&#xff0c;知道方向和资料从哪里去找。 二.参考标准 要管理企业的大数据&#xff0c;从什么地方开始呢&#xff1f;首先应该完成企业数据的分类、分级&#xff0c;或者参…

一文掌握python常用的dict(字典)操作

目录 一、字典的创建与基本特性 1.创建字典 2.字典的基本特性 二、字典的常用操作 1.访问字典中的值 2.添加、修改键值对 3.删除键值对 4.获取字典中的所有键、值和键值对 5.遍历字典 6.查找键是否存在 7.使用 get() 方法获取值 8.合并字典 9.字典排序 10.使用字…