From fc39185e2847422c6da5cdef0fbb5130242bd60b Mon Sep 17 00:00:00 2001 From: luogw <3132758203@qq.com> Date: Sat, 21 Mar 2026 11:10:28 +0800 Subject: [PATCH] =?UTF-8?q?bug=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project/interaction/utils/NotifyUtil.java | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/project/interaction/utils/NotifyUtil.java b/src/main/java/com/project/interaction/utils/NotifyUtil.java index ff943ed..d5c28be 100644 --- a/src/main/java/com/project/interaction/utils/NotifyUtil.java +++ b/src/main/java/com/project/interaction/utils/NotifyUtil.java @@ -11,6 +11,7 @@ import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.time.Duration; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -31,30 +32,34 @@ public class NotifyUtil { "01231011386731976125", "590204300932000212" ); - // 防重复缓存key前缀 + // 防重复缓存 key 前缀 private static final String WARN_LOCK_KEY_PREFIX = "question:gen:warn:lock:"; - // 重复发送间隔:1小时(3600秒) + // 重复发送间隔:1 小时(3600 秒) private static final long WARN_LOCK_EXPIRE_SECONDS = 3600L; public void notify(Long taskId,Long clusterId) { - // 构建Redis缓存key(按taskId唯一) + // 构建 Redis 缓存 key(按 taskId 唯一) String cacheKey = WARN_LOCK_KEY_PREFIX + taskId; - // 核心逻辑:检查Redis缓存,存在则直接返回(1小时内已发送过) - boolean isCached = redissonClient.getBucket(cacheKey).isExists(); - if (isCached) { + // 核心逻辑:使用原子操作 setIfAbsent 防止并发重复发送 + // 返回 true 表示成功设置(之前不存在),返回 false 表示 1 小时内已发送过 + boolean acquired = redissonClient.getBucket(cacheKey).setIfAbsent( + "SEND_SUCCESS", + Duration.ofSeconds(WARN_LOCK_EXPIRE_SECONDS) + ); + if (!acquired) { + log.debug(">>> [算法生题 API 调用失败通知] 任务{}在 1 小时内已发送过,跳过", taskId); return; } - try { String now = DateUtil.now(); - String markdown = String.format("### 【告警】算法生题API调用失败通知 \n\n") + + String markdown = String.format("### 【告警】算法生题 API 调用失败通知 \n\n") + String.format("## 核心信息\n") + - String.format("- 考试任务ID:%d\n", taskId) + - String.format("- 知识点簇ID:%d\n", clusterId) + + String.format("- 考试任务 ID:%d\n", taskId) + + String.format("- 知识点簇 ID:%d\n", clusterId) + String.format("- 当前时间:%s\n\n", now) + String.format("## 异常说明\n") + String.format("算法服务生成题目时调用失败,可能导致考试题目不完整或无法正常作答,请尽快排查以下问题:\n") + @@ -63,21 +68,20 @@ public class NotifyUtil { .agentId(dtService.getDtConfigStorage().getAgentId()) .userIds(WARN_USER_LIST) .msg(DtMessage.MARKDOWN() - .content("算法生题API调用失败通知") + .content("算法生题 API 调用失败通知") .text(markdown) .build()) .build(); DtCorpConversationMsgSendResult result = dtService.getCorpConversationMsgService().send(corpConversationMessage); if (result.getErrCode() == 0) { - log.info(">>> [算法生题API调用失败通知] 成功发送通知 ,考试任务ID:{} ,知识点簇ID:{}", taskId, clusterId); + log.info(">>> [算法生题 API 调用失败通知] 成功发送通知,考试任务 ID:{} ,知识点簇 ID:{}", taskId, clusterId); } else { - log.error(">>> [算法生题API调用失败通知] 发送失败.考试任务ID:{} ,知识点簇ID:{}, 错误码: {}, 错误信息: {}", taskId, clusterId, + log.error(">>> [算法生题 API 调用失败通知] 发送失败,考试任务 ID:{} ,知识点簇 ID:{}, 错误码:{}, 错误信息:{}", taskId, clusterId, result.getErrCode(), result.getErrMsg()); } - redissonClient.getBucket(cacheKey).set("SEND_SUCCESS", WARN_LOCK_EXPIRE_SECONDS, TimeUnit.SECONDS); } catch (Exception e) { - log.error(">>> [算法生题API调用失败通知] 钉钉接口调用异常, 考试任务ID:{} ,知识点簇ID:{}, 原因: {}",taskId, clusterId, e.getMessage()); + log.error(">>> [算法生题 API 调用失败通知] 钉钉接口调用异常,考试任务 ID:{} ,知识点簇 ID:{}, 原因:{}",taskId, clusterId, e.getMessage()); } } }