From 266087973f2eaa9b54f344abab260c6e3450b889 Mon Sep 17 00:00:00 2001 From: tianyongbao Date: Thu, 19 Mar 2026 07:51:20 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=96=B0=E5=A2=9E=E5=AE=9A=E6=97=B6?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=EF=BC=8C=E9=A5=B1=E5=92=8C=E5=BA=A6=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/task/DeviceSaturaHighWarnTask.java | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 intc-modules/intc-iot/src/main/java/com/intc/iot/task/DeviceSaturaHighWarnTask.java diff --git a/intc-modules/intc-iot/src/main/java/com/intc/iot/task/DeviceSaturaHighWarnTask.java b/intc-modules/intc-iot/src/main/java/com/intc/iot/task/DeviceSaturaHighWarnTask.java new file mode 100644 index 0000000..4860051 --- /dev/null +++ b/intc-modules/intc-iot/src/main/java/com/intc/iot/task/DeviceSaturaHighWarnTask.java @@ -0,0 +1,80 @@ +package com.intc.iot.task; + +import com.intc.common.redis.utils.RedisUtils; +import com.intc.iot.config.AliyunIotProperties; +import com.intc.iot.handler.DeviceDataHandler; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Collection; + +/** + * 夜间溶解氧饱和度持续超阈告警延迟触发定时任务 + * 对应 C# UpdateDataSecondlyJob.CheckWarnAndNotice 中对 SaturaHigh WarnWait 的处理: + * 夜间(20:00-08:00)饱和度 >= 200% 持续超过配置的 saturability-warn-hours 小时才真正触发告警。 + * + * @author intc-iot + */ +@Slf4j +@Component +@RequiredArgsConstructor +@ConditionalOnBean(DeviceDataHandler.class) +public class DeviceSaturaHighWarnTask { + + private static final String SATURA_WAIT_KEY_PREFIX = "device:satura:wait:"; + + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + private final DeviceDataHandler deviceDataHandler; + + private final AliyunIotProperties aliyunIotProperties; + + /** + * 每分钟扫描一次饱和度超阈等待标记 + * 对超过配置的 saturability-warn-hours 小时的设备触发告警 + */ + @Scheduled(fixedDelay = 60000) + public void checkSaturaWaitAndTrigger() { + try { + Collection keys = RedisUtils.keys(SATURA_WAIT_KEY_PREFIX + "*"); + if (keys == null || keys.isEmpty()) { + return; + } + + LocalDateTime now = LocalDateTime.now(); + int warnHours = aliyunIotProperties.getSaturabilityWarnHours(); + + for (String key : keys) { + try { + String firstExceedTimeStr = RedisUtils.getCacheObject(key); + if (firstExceedTimeStr == null) { + continue; + } + + LocalDateTime firstExceedTime = LocalDateTime.parse(firstExceedTimeStr, FORMATTER); + long elapsedHours = java.time.Duration.between(firstExceedTime, now).toHours(); + + if (elapsedHours >= warnHours) { + // 提取 deviceName(去掉前缀) + String deviceName = key.substring(SATURA_WAIT_KEY_PREFIX.length()); + + // 触发告警前先删除标记,防止重复触发 + RedisUtils.deleteObject(key); + + log.info("[饱和度告警] 设备夜间饱和度持续超阈已达 {} 小时,触发告警: {}", elapsedHours, deviceName); + deviceDataHandler.triggerSaturaHighAlarm(deviceName); + } + } catch (Exception e) { + log.error("[饱和度告警] 处理单条等待标记异常,key={}: {}", key, e.getMessage(), e); + } + } + } catch (Exception e) { + log.error("[饱和度告警] 扫描等待标记异常: {}", e.getMessage(), e); + } + } +}