fix: 应该每次电话报警,就新增条消息,不能每次超过阈值就生成一条报警。

This commit is contained in:
tianyongbao
2026-03-18 22:36:13 +08:00
parent cd1e8249ce
commit 975eb308a3
2 changed files with 68 additions and 5 deletions

View File

@@ -1,8 +1,12 @@
package com.intc.fishery.mapper; package com.intc.fishery.mapper;
import com.intc.common.mybatis.core.mapper.BaseMapperPlusJoin; import com.intc.common.mybatis.core.mapper.BaseMapperPlusJoin;
import com.intc.fishery.domain.MessageWarn; import com.intc.fishery.domain.MessageWarn;
import com.intc.fishery.domain.vo.MessageWarnVo; import com.intc.fishery.domain.vo.MessageWarnVo;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.Date;
/** /**
* 设备告警记录Mapper接口 * 设备告警记录Mapper接口
@@ -12,4 +16,18 @@ import com.intc.fishery.domain.vo.MessageWarnVo;
*/ */
public interface MessageWarnMapper extends BaseMapperPlusJoin<MessageWarn, MessageWarnVo> { public interface MessageWarnMapper extends BaseMapperPlusJoin<MessageWarn, MessageWarnVo> {
/**
* 查询指定设备、告警标题、时间范围内的告警消息数量
* 用于对未开启电话通知的告警类型做时间窗口抑制,避免每次超阈值都重复写入记录
*
* @param deviceId 设备ID
* @param title 告警标题
* @param afterTime 起始时间
* @return 满足条件的告警消息数量
*/
@Select("SELECT COUNT(1) FROM aqu_message_warn WHERE device_id = #{deviceId} AND title = #{title} AND create_time >= #{afterTime}")
long countByDeviceAndTitleAfter(@Param("deviceId") Long deviceId,
@Param("title") String title,
@Param("afterTime") Date afterTime);
} }

View File

@@ -441,16 +441,55 @@ public class DeviceDataHandler {
} }
} }
// 如果有告警,保存全部报警消息记录 // 如果有告警,处理报警消息记录
if (hasAlarm) { if (hasAlarm) {
log.warn("[告警] {} - {}", deviceName, alarmMessage); log.warn("[告警] {} - {}", deviceName, alarmMessage);
// 批量保存报警消息(无论是否开启电话通知,告警记录始终生成 // 计算抑制时间窗口(与电话通知保持一致
LocalDateTime suppressTime = LocalDateTime.now().minusHours(aliyunIotProperties.getCallSuccessSuppressHours());
java.util.Date suppressDate = java.util.Date.from(suppressTime.atZone(java.time.ZoneId.systemDefault()).toInstant());
int maxBatchMinutesForCheck = CALL_NOTICE_RETRY_COUNT * CALL_NOTICE_MINUTE_INTERVAL * 2;
LocalDateTime activeBatchStartForCheck = LocalDateTime.now().minusMinutes(maxBatchMinutesForCheck);
LocalDateTime periodStartForCheck = getCurrentPeriodStart();
// 对未开启电话通知的告警类型,做时间窗口抑制后再插入消息记录
// 对开启了电话通知的类型MessageWarn 由 triggerAlarmNotification 在通过抑制判断后统一插入
for (MessageWarn warn : warnList) { for (MessageWarn warn : warnList) {
// 跳过已加入电话通知列表的告警(由 triggerAlarmNotification 负责插入)
if (callWarnList.contains(warn)) {
continue;
}
// 判断该类型告警是否开启了免打扰
boolean noDisturbForWarn = false;
if (ALARM_TYPE_DISSOLVED_OXYGEN.equals(warn.getTitle()) &&
device.getOxyWarnCallNoDis() != null && device.getOxyWarnCallNoDis() == 1) {
noDisturbForWarn = true;
} else if ((ALARM_TYPE_TEMPERATURE_HIGH.equals(warn.getTitle()) || ALARM_TYPE_TEMPERATURE_LOW.equals(warn.getTitle())) &&
device.getTempWarnCallNoDis() != null && device.getTempWarnCallNoDis() == 1) {
noDisturbForWarn = true;
} else if (ALARM_TYPE_BATTERY.equals(warn.getTitle()) &&
device.getBatteryWarnCallNoDis() != null && device.getBatteryWarnCallNoDis() == 1) {
noDisturbForWarn = true;
}
// 按抑制规则判断是否应跳过
boolean shouldSkip;
if (noDisturbForWarn) {
java.util.Date periodStartDate = java.util.Date.from(periodStartForCheck.atZone(java.time.ZoneId.systemDefault()).toInstant());
shouldSkip = messageWarnMapper.countByDeviceAndTitleAfter(deviceId, warn.getTitle(), periodStartDate) > 0;
} else {
java.util.Date activeBatchStartDate = java.util.Date.from(activeBatchStartForCheck.atZone(java.time.ZoneId.systemDefault()).toInstant());
shouldSkip = messageWarnMapper.countByDeviceAndTitleAfter(deviceId, warn.getTitle(), activeBatchStartDate) > 0
|| messageWarnMapper.countByDeviceAndTitleAfter(deviceId, warn.getTitle(), suppressDate) > 0;
}
if (!shouldSkip) {
messageWarnMapper.insert(warn); messageWarnMapper.insert(warn);
log.debug("[告警] {} title={} 新增消息记录", deviceName, warn.getTitle());
} else {
log.debug("[告警] {} title={} 抑制期内已有记录,跳过消息写入", deviceName, warn.getTitle());
}
} }
// 仅对开启了电话通知开关的告警触发电话通知 // 仅对开启了电话通知开关的告警触发电话通知MessageWarn 由通知方法内部插入)
if (!callWarnList.isEmpty()) { if (!callWarnList.isEmpty()) {
triggerAlarmNotification(device, alarmMessage.toString(), sensorData, callWarnList); triggerAlarmNotification(device, alarmMessage.toString(), sensorData, callWarnList);
} }
@@ -565,6 +604,12 @@ public class DeviceDataHandler {
// 告警内容(取该类型第一条) // 告警内容(取该类型第一条)
String typeAlarmMessage = typeWarnList.get(0).getMessage(); String typeAlarmMessage = typeWarnList.get(0).getMessage();
// 通过抑制判断,先插入 MessageWarn 记录(每次电话报警才新增一条消息)
for (MessageWarn warn : typeWarnList) {
messageWarnMapper.insert(warn);
}
log.debug("[告警] {} title={} 通过抑制,已插入 {} 条告警消息记录", deviceName, title, typeWarnList.size());
// 为每个手机号 × 重试次数创建通知记录callTime 按间隔错开 // 为每个手机号 × 重试次数创建通知记录callTime 按间隔错开
// 参考 C#: CallNoticeRetryCount=3, CallNoticeMinuteInterval=3 // 参考 C#: CallNoticeRetryCount=3, CallNoticeMinuteInterval=3
// 立即尝试发送第一个号码;若失败则后续通知记录会在定时任务中按时间发送 // 立即尝试发送第一个号码;若失败则后续通知记录会在定时任务中按时间发送