聊聊PowerJob的Alarmable
序
本文主要研究一下PowerJob的Alarmable
Alarmable
tech/powerjob/server/extension/Alarmable.java
public interface Alarmable {void onFailed(Alarm alarm, List<UserInfoDO> targetUserList);
}
Alarmable接口定义了onFailed方法,其入参为alarm及targetUserList
Alarm
public interface Alarm extends PowerSerializable {String fetchTitle();default String fetchContent() {StringBuilder sb = new StringBuilder();JSONObject content = JSONObject.parseObject(JSONObject.toJSONString(this));content.forEach((key, originWord) -> {sb.append(key).append(": ");String word = String.valueOf(originWord);if (StringUtils.endsWithIgnoreCase(key, "time") || StringUtils.endsWithIgnoreCase(key, "date")) {try {if (originWord instanceof Long) {word = CommonUtils.formatTime((Long) originWord);}}catch (Exception ignore) {}}sb.append(word).append(OmsConstant.LINE_SEPARATOR);});return sb.toString();}
}
Alarm定义了fetchTitle方法,提供了fetchContent默认方法,它有两个实现类分别是JobInstanceAlarm、WorkflowInstanceAlarm
DingTalkAlarmService
tech/powerjob/server/extension/defaultimpl/alarm/impl/DingTalkAlarmService.java
@Slf4j
@Service
@RequiredArgsConstructor
public class DingTalkAlarmService implements Alarmable {private final Environment environment;private Long agentId;private DingTalkUtils dingTalkUtils;private Cache<String, String> mobile2UserIdCache;private static final int CACHE_SIZE = 8192;/*** 防止缓存击穿*/private static final String EMPTY_TAG = "EMPTY";@Overridepublic void onFailed(Alarm alarm, List<UserInfoDO> targetUserList) {if (dingTalkUtils == null) {return;}Set<String> userIds = Sets.newHashSet();targetUserList.forEach(user -> {String phone = user.getPhone();if (StringUtils.isEmpty(phone)) {return;}try {String userId = mobile2UserIdCache.get(phone, () -> {try {return dingTalkUtils.fetchUserIdByMobile(phone);} catch (PowerJobException ignore) {return EMPTY_TAG;} catch (Exception ignore) {return null;}});if (!EMPTY_TAG.equals(userId)) {userIds .add(userId);}}catch (Exception ignore) {}});userIds.remove(null);if (!userIds.isEmpty()) {String userListStr = SJ.COMMA_JOINER.skipNulls().join(userIds);List<DingTalkUtils.MarkdownEntity> markdownEntities = Lists.newLinkedList();markdownEntities.add(new DingTalkUtils.MarkdownEntity("server", NetUtils.getLocalHost()));String content = alarm.fetchContent().replaceAll(OmsConstant.LINE_SEPARATOR, OmsConstant.COMMA);markdownEntities.add(new DingTalkUtils.MarkdownEntity("content", content));try {dingTalkUtils.sendMarkdownAsync(alarm.fetchTitle(), markdownEntities, userListStr, agentId);}catch (Exception e) {log.error("[DingTalkAlarmService] send ding message failed, reason is {}", e.getMessage());}}}@PostConstructpublic void init() {String agentId = environment.getProperty(PowerJobServerConfigKey.DING_AGENT_ID);String appKey = environment.getProperty(PowerJobServerConfigKey.DING_APP_KEY);String appSecret = environment.getProperty(PowerJobServerConfigKey.DING_APP_SECRET);log.info("[DingTalkAlarmService] init with appKey:{},appSecret:{},agentId:{}", appKey, appSecret, agentId);if (StringUtils.isAnyBlank(agentId, appKey, appSecret)) {log.warn("[DingTalkAlarmService] cannot get agentId, appKey, appSecret at the same time, this service is unavailable");return;}if (!StringUtils.isNumeric(agentId)) {log.warn("[DingTalkAlarmService] DingTalkAlarmService is unavailable due to invalid agentId: {}", agentId);return;}this.agentId = Long.valueOf(agentId);dingTalkUtils = new DingTalkUtils(appKey, appSecret);mobile2UserIdCache = CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).softValues().build();log.info("[DingTalkAlarmService] init DingTalkAlarmService successfully!");}}
DingTalkAlarmService实现了Alarmable接口,其onFailed遍历targetUserList获取userId,最后通过dingTalkUtils.sendMarkdownAsync发送
MailAlarmService
tech/powerjob/server/extension/defaultimpl/alarm/impl/MailAlarmService.java
@Slf4j
@Service
public class MailAlarmService implements Alarmable {@Resourceprivate Environment environment;private JavaMailSender javaMailSender;@Value("${spring.mail.username:''}")private String from;@Overridepublic void onFailed(Alarm alarm, List<UserInfoDO> targetUserList) {if (CollectionUtils.isEmpty(targetUserList) || javaMailSender == null || StringUtils.isEmpty(from)) {return;}SimpleMailMessage sm = new SimpleMailMessage();try {sm.setFrom(from);sm.setTo(targetUserList.stream().map(UserInfoDO::getEmail).filter(Objects::nonNull).toArray(String[]::new));sm.setSubject(alarm.fetchTitle());sm.setText(alarm.fetchContent());javaMailSender.send(sm);}catch (Exception e) {log.warn("[MailAlarmService] send mail failed, reason is {}", e.getMessage());}}@Autowired(required = false)public void setJavaMailSender(JavaMailSender javaMailSender) {this.javaMailSender = javaMailSender;}}
MailAlarmService实现了Alarmable接口,其onFailed方法构建SimpleMailMessage,然后通过spring的javaMailSender.send发送
WebHookAlarmService
tech/powerjob/server/extension/defaultimpl/alarm/impl/WebHookAlarmService.java
@Slf4j
@Service
public class WebHookAlarmService implements Alarmable {private static final String HTTP_PROTOCOL_PREFIX = "http://";private static final String HTTPS_PROTOCOL_PREFIX = "https://";@Overridepublic void onFailed(Alarm alarm, List<UserInfoDO> targetUserList) {if (CollectionUtils.isEmpty(targetUserList)) {return;}targetUserList.forEach(user -> {String webHook = user.getWebHook();if (StringUtils.isEmpty(webHook)) {return;}// 自动添加协议头if (!webHook.startsWith(HTTP_PROTOCOL_PREFIX) && !webHook.startsWith(HTTPS_PROTOCOL_PREFIX)) {webHook = HTTP_PROTOCOL_PREFIX + webHook;}MediaType jsonType = MediaType.parse(OmsConstant.JSON_MEDIA_TYPE);RequestBody requestBody = RequestBody.create(jsonType, JSONObject.toJSONString(alarm));try {String response = HttpUtils.post(webHook, requestBody);log.info("[WebHookAlarmService] invoke webhook[url={}] successfully, response is {}", webHook, response);}catch (Exception e) {log.warn("[WebHookAlarmService] invoke webhook[url={}] failed!", webHook, e);}});}
}
WebHookAlarmService实现了Alarmable接口,其onFailed方法遍历targetUserList,挨个执行HttpUtils.post(webHook, requestBody),用的是okhttp3来实现http请求回调
小结
PowerJob的Alarmable接口定义了onFailed方法,其入参为alarm及targetUserList;它有三个实现类,分别是DingTalkAlarmService(用的是DingTalkClient)、MailAlarmService(用的是spring的JavaMailSender)、WebHookAlarmService(用的是okhttp3的OkHttpClient)。
相关文章:
聊聊PowerJob的Alarmable
序 本文主要研究一下PowerJob的Alarmable Alarmable tech/powerjob/server/extension/Alarmable.java public interface Alarmable {void onFailed(Alarm alarm, List<UserInfoDO> targetUserList); }Alarmable接口定义了onFailed方法,其入参为alarm及tar…...
系列三十五、获取Excel中的总记录数
一、获取Excel中的总记录数 1.1、概述 使用EasyExcel开发进行文件上传时,通常会碰到一个问题,那就是Excel中的记录数太多,使用传统的方案进行文件上传,很容易就超时了,这时可以通过对用户上传的Excel中的数量进行限制…...
VMware workstation安装debian-12.1.0虚拟机并配置网络
VMware workstation安装debian-12.1.0虚拟机并配置网络 Debian 是一个完全自由的操作系统!Debian 有一个由普罗大众组成的社区!该文档适用于在VMware workstation平台安装debian-12.1.0虚拟机。 1.安装准备 1.1安装平台 Windows 11 1.2软件信息 软…...
centos下系统全局检测工具dstat使用
目录 一:没有需要安装 二:dstat命令参数 三、监测界面各参数含义(部分) 四、dstat的高级用法 一:没有需要安装 yum install dstat 二:dstat命令参数 有默认选项,执行dstat命令不加任何参数…...
无人机群ros通信
单架无人机与地面站通信 在一个局域网内获取无人机的机载电脑ip 通过地面站ssh到机载电脑,实现通信 多架无人机与地面站通信 在ROS基础上,配置主机和从机,实现主机和从机的话题联通 配置hosts 在主机和从机的/etc/hosts文件中,…...
LeetCode刷题:142. 环形链表 II
题目: 是否独立解决:否,参考了解题思路解决问题,思考了用快慢指针,栈,统计链表数量定位尾巴节点(因为是环形链表所以是死循环,链表数量用while循环统计不出来)都没解决 解…...
Laravel 使用rdkafka_laravel详细教程(实操避坑)
一、选择rdkafka 首先要看版本兼容问题,我的是Laravel5.6,PHP是7.3.13,所以需要下载兼容此的rdkafka,去 Packagist 搜索 kafka ,我用的是 enqueue/rdkafka选择里面0.10.5版本, 二、安装rdkafka 在 Larav…...
439 - Knight Moves (UVA)
题目链接如下: Online Judge UVA439 骑士的移动 - 锦依卫议事堂 - 洛谷博客 这里有好几个特别厉害的解法...先存着慢慢看。 我的代码如下: #include <iostream> #include <deque> #include <string> // #define debugstruct node{…...
数据结构(c)冒泡排序
本文除了最下面的代码是我写的,其余是网上抄写的。 冒泡排序 什么是冒泡排序? 冒泡排序(Bubble Sort)是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交…...
并发编程之并发容器
目录 并发容器 CopyOnWriteArrayList 应用场景 常用方法 读多写少场景使用CopyOnWriteArrayList举例 CopyOnWriteArrayList原理 CopyOnWriteArrayList 的缺陷 扩展迭代器fail-fast与fail-safe机制 ConcurrentHashMap 应用场景 常用方法 并发场景下线程安全举例 Con…...
K8s---存储卷(动态pv和pvc)
当我要发布pvc可以生成pv,还可以共享服务器上直接生成挂载目录。pvc直接绑定pv。 动态pv需要两个组件 1、卷插件:k8s本生支持的动态pv创建不包括nfs,需要声明和安装一个外部插件 Provisioner: 存储分配器。动态创建pv,然后根据pvc的请求自动…...
JS判断对象是否为空对象的几种方法
通过JSON自带的stringify()方法判断 function isEmptyObj(obj) {return JSON.stringify(obj) {} } console.log(对象是否为空:, isEmptyObj({}))for in 循环判断 function isEmptyObj(obj) {for(let item in obj) {return true}return false } console.log(对…...
算法通关村第十五关—用4KB内存寻找重复元素(青铜)
用4KB内存寻找重复元素 用4KB内存寻找重复元素 题目要求:给定一个数组,包含从1到N的整数,N最大为32000,数组可能还有重复值,且N的取值不定,若只有4KB的内存可用,该如何打印数组中所有重复元素。…...
【PHP】判断字符串是否是有效的base64编码
目录 1.检测长度: 2.检查字符集: 3.判断是否能正常解码 在PHP中,判断一个字符串是否是有效的Base64编码,可以通过以下几种方法: 1.检测长度: Base64编码的字符串长度必须是4的倍数(对于标准…...
鼎盛合|测量精度SOC芯片开发中的技术问题整理
SOC芯片近几年的发展势头迅猛,许多行业中俱可见其身影。SOC芯片并不是传统意义上的芯片,它是一个由多种功能集成的一个芯片。SOC芯片自身在出厂时便带有部分程序,是为了方便设计开发而针对某些行业设计的特定功能。如芯海的SOC芯片大多数则是…...
sql | 学生参加各科考试次数
学生表: Students------------------------ | Column Name | Type | ------------------------ | student_id | int | | student_name | varchar | ------------------------ 在 SQL 中,主键为 student_id(学生ID)。 该表内的每…...
uniapp(vue2)+VoerkaI18n多语言
今天我学习了VoerkaI18n国际化插件,它是一个适用于Javascript/Vue/React/Solid/ReactNative的国际化全流程解决方案。VoerkaI18n可以帮助我们轻松地实现应用程序的多语言支持,使得应用程序可以适应不同的语言环境。 比较吸引我的是集成自动翻译,t(“中华…...
C51--测速小车
测速小车: 测速模块: 用途: 广泛用于电机转速检测,脉冲计数,位置限位等。 高低电平: 有遮挡,输出高电平; 无遮挡,输出低电平。 接线: VCC——正极 GND——接…...
ORACLE报错:ORA-04091 表XXX发生了变化,触发器/函数不能读它
ORACLE报错:ORA-04091 表发XXX生了变化,触发器/函数不能读它 问题描述问题分析解决办法拓展:自治事务的特点 问题描述 在开发校验函数FUNCTION的时候,用数据跑批测试的时候报错。经排查这个校验函数FUNCTION的被一个存储过程中的update语句调…...
Arm LDM和STM的寻址方式
A32指令集中包含多数据传输指令LDM和STM,也就是单条指令可以传输多个寄存器的值与内存交互,这对于数据块传输以及寄存器的压入栈很有帮助。LDM和STM指令可分别用于实现堆栈的pop和push操作。对于堆栈操作,基寄存器通常是堆栈指针(SP)。 LDM和…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分: 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...
【Ftrace 专栏】Ftrace 参考博文
ftrace、perf、bcc、bpftrace、ply、simple_perf的使用Ftrace 基本用法Linux 利用 ftrace 分析内核调用如何利用ftrace精确跟踪特定进程调度信息使用 ftrace 进行追踪延迟Linux-培训笔记-ftracehttps://www.kernel.org/doc/html/v4.18/trace/events.htmlhttps://blog.csdn.net/…...
dvwa11——XSS(Reflected)
LOW 分析源码:无过滤 和上一关一样,这一关在输入框内输入,成功回显 <script>alert(relee);</script> MEDIUM 分析源码,是把<script>替换成了空格,但没有禁用大写 改大写即可,注意函数…...
