补充mtragent管理初版
This commit is contained in:
+1
-1
@@ -55,7 +55,7 @@ public class RocketMsgListener implements MessageListenerConcurrently {
|
|||||||
log.error("消息消费三次失败,消息内容:{}", body);
|
log.error("消息消费三次失败,消息内容:{}", body);
|
||||||
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;//根据业务返回是否正常
|
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;//根据业务返回是否正常
|
||||||
}
|
}
|
||||||
if(MessageCodeEnum.TR_AGENT_UP.getCode().equals(topic)){
|
if(MessageCodeEnum.TR_MTRAGENT_UP.getCode().equals(topic)){
|
||||||
// 拿到信息
|
// 拿到信息
|
||||||
DeviceMessage message = JSON.parseObject(body, DeviceMessage.class);
|
DeviceMessage message = JSON.parseObject(body, DeviceMessage.class);
|
||||||
// 处理消息
|
// 处理消息
|
||||||
|
|||||||
+2
@@ -19,6 +19,8 @@ public enum MessageCodeEnum {
|
|||||||
|
|
||||||
TR_AGENT_UP("tr_agent_up","agent数据采集的信息topic v1.1"),
|
TR_AGENT_UP("tr_agent_up","agent数据采集的信息topic v1.1"),
|
||||||
|
|
||||||
|
TR_MTRAGENT_UP("tr_mtragent_up","mtragent监测丢包率的信息topic"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 系统消息
|
* 系统消息
|
||||||
*/
|
*/
|
||||||
|
|||||||
+465
-11
@@ -1,20 +1,36 @@
|
|||||||
package com.ruoyi.mtragent.handler;
|
package com.ruoyi.mtragent.handler;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.ruoyi.common.core.constant.SecurityConstants;
|
||||||
|
import com.ruoyi.common.core.domain.R;
|
||||||
import com.ruoyi.common.core.enums.MsgEnum;
|
import com.ruoyi.common.core.enums.MsgEnum;
|
||||||
import com.ruoyi.mtragent.domain.DeviceMessage;
|
import com.ruoyi.common.core.utils.DateUtils;
|
||||||
|
import com.ruoyi.common.core.utils.StringUtils;
|
||||||
|
import com.ruoyi.mtragent.domain.*;
|
||||||
|
import com.ruoyi.mtragent.domain.vo.MessageVo;
|
||||||
|
import com.ruoyi.mtragent.domain.vo.RegisterMsgVo;
|
||||||
import com.ruoyi.mtragent.domain.vo.RspVo;
|
import com.ruoyi.mtragent.domain.vo.RspVo;
|
||||||
import com.ruoyi.mtragent.service.IRmAgentManagementService;
|
import com.ruoyi.mtragent.enums.AlarmTypeEnum;
|
||||||
|
import com.ruoyi.mtragent.enums.PushMethodEnum;
|
||||||
|
import com.ruoyi.mtragent.producer.MessageProducer;
|
||||||
|
import com.ruoyi.mtragent.service.*;
|
||||||
import com.ruoyi.mtragent.utils.JsonDataParser;
|
import com.ruoyi.mtragent.utils.JsonDataParser;
|
||||||
|
import com.ruoyi.mtragent.utils.WeChatWorkBot;
|
||||||
|
import com.ruoyi.system.api.RemoteRevenueConfigService;
|
||||||
|
import com.ruoyi.system.api.domain.NetworkInfo;
|
||||||
|
import com.ruoyi.system.api.domain.RmSwitchManagementRemote;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.dao.DataAccessException;
|
||||||
|
import org.springframework.data.redis.core.RedisOperations;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.core.SessionCallback;
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,14 +43,14 @@ public class MessageHandler {
|
|||||||
|
|
||||||
private final Map<String, Consumer<DeviceMessage>> messageHandlers = new HashMap<>();
|
private final Map<String, Consumer<DeviceMessage>> messageHandlers = new HashMap<>();
|
||||||
// 心跳状态
|
// 心跳状态
|
||||||
private static final String HEARTBEAT_STATUS_PREFIX = "heartbeat:status:";
|
private static final String HEARTBEAT_STATUS_PREFIX = "mtr:heartbeat:status:";
|
||||||
// 心跳时间
|
// 心跳时间
|
||||||
private static final String HEARTBEAT_TIME_PREFIX = "heartbeat:time:";
|
private static final String HEARTBEAT_TIME_PREFIX = "mtr:heartbeat:time:";
|
||||||
// 心跳告警
|
// 心跳告警
|
||||||
private static final String HEARTBEAT_ALERT_PREFIX = "heartbeat:alert:";
|
private static final String HEARTBEAT_ALERT_PREFIX = "mtr:heartbeat:alert:";
|
||||||
String HEARTBEAT_RECOVERY_COUNT_PREFIX = "heartbeat:recovery:count:";
|
String HEARTBEAT_RECOVERY_COUNT_PREFIX = "mtr:heartbeat:recovery:count:";
|
||||||
|
|
||||||
String HEARTBEAT_COUNT_PREFIX = "heartbeat:count:";
|
String HEARTBEAT_COUNT_PREFIX = "mtr:heartbeat:count:";
|
||||||
private static final long HEARTBEAT_TIMEOUT = 30000; // 3分钟超时
|
private static final long HEARTBEAT_TIMEOUT = 30000; // 3分钟超时
|
||||||
|
|
||||||
|
|
||||||
@@ -42,6 +58,18 @@ public class MessageHandler {
|
|||||||
private RedisTemplate<String, String> redisTemplate;
|
private RedisTemplate<String, String> redisTemplate;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IRmAgentManagementService rmAgentManagementService;
|
private IRmAgentManagementService rmAgentManagementService;
|
||||||
|
@Autowired
|
||||||
|
private RemoteRevenueConfigService remoteRevenueConfigService;
|
||||||
|
@Autowired
|
||||||
|
private IRmAlarmPushConfigService rmAlarmPushConfigService;
|
||||||
|
@Autowired
|
||||||
|
private IRmAlarmLogService rmAlarmLogService;
|
||||||
|
@Autowired
|
||||||
|
private IInitialHeartbeatListenLogService initialHeartbeatListenLogService;
|
||||||
|
@Autowired
|
||||||
|
private IRmNetworkInterfaceService rmNetworkInterfaceService;
|
||||||
|
@Autowired
|
||||||
|
private IRmMtrClientRegistrationService rmMtrClientRegistrationService;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,9 +81,54 @@ public class MessageHandler {
|
|||||||
|
|
||||||
// 其他类型消息可以单独注册处理器
|
// 其他类型消息可以单独注册处理器
|
||||||
registerHandler(MsgEnum.注册.getValue(), this::handleRegisterMessage);
|
registerHandler(MsgEnum.注册.getValue(), this::handleRegisterMessage);
|
||||||
|
registerHandler(MsgEnum.心跳上报.getValue(), this::handleHeartbeatMessage);
|
||||||
|
registerHandler(MsgEnum.多公网IP探测.getValue(), this::handleNetWorkDelectMessage);
|
||||||
}
|
}
|
||||||
private void handleRegisterMessage(DeviceMessage message) {
|
private void handleRegisterMessage(DeviceMessage message) {
|
||||||
|
MessageProducer messageProducer = new MessageProducer();
|
||||||
|
List<RegisterMsgVo> interfaces = JsonDataParser.parseJsonData(message.getData(), RegisterMsgVo.class);
|
||||||
|
if(!interfaces.isEmpty()) {
|
||||||
|
String clientId = message.getClientId();
|
||||||
|
RegisterMsgVo registerMsg = interfaces.get(0);
|
||||||
|
// 时间戳转换
|
||||||
|
long timestamp = registerMsg.getTimestamp();
|
||||||
|
long millis = timestamp * 1000;
|
||||||
|
Date createTime = new Date(millis / 1000 * 1000); // 去除毫秒
|
||||||
|
String timeStr = DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", createTime);
|
||||||
|
List<NetworkInfo> networkInfoList = registerMsg.getNetworkInfo();
|
||||||
|
if(!networkInfoList.isEmpty()){
|
||||||
|
RmMtrClientRegistration rmMtrClientRegistrationQuery = new RmMtrClientRegistration();
|
||||||
|
rmMtrClientRegistrationQuery.setMtrClientId(clientId);
|
||||||
|
List<RmMtrClientRegistration> mtrClientRegistrationList = rmMtrClientRegistrationService.selectRmMtrClientRegistrationList(rmMtrClientRegistrationQuery);
|
||||||
|
if(mtrClientRegistrationList == null || mtrClientRegistrationList.isEmpty()){
|
||||||
|
// 构建mtrClient信息
|
||||||
|
RmMtrClientRegistration insertData = new RmMtrClientRegistration();
|
||||||
|
try {
|
||||||
|
insertData.setMtrClientId(registerMsg.getClientId());
|
||||||
|
insertData.setRegisterStatus("1");
|
||||||
|
insertData.setHeartbeatCount(3);
|
||||||
|
insertData.setHeartbeatInterval(30);
|
||||||
|
insertData.setCreateTime(createTime);
|
||||||
|
insertData.setRegisterTime(createTime);
|
||||||
|
insertData.setNetworkInfo(JSONObject.toJSONString(networkInfoList));
|
||||||
|
rmMtrClientRegistrationService.insertRmMtrClientRegistration(insertData);
|
||||||
|
// 构建注册应答信息
|
||||||
|
MessageVo messageVo = new MessageVo();
|
||||||
|
messageVo.setClientId(registerMsg.getClientId());
|
||||||
|
messageVo.setDataType(MsgEnum.注册应答.getValue());
|
||||||
|
RspVo rspVo = new RspVo();
|
||||||
|
rspVo.setResCode(1);
|
||||||
|
rspVo.setResMag("注册成功");
|
||||||
|
messageVo.setData(JSONObject.toJSONString(rspVo));
|
||||||
|
messageProducer.sendAsyncProducerMessage(
|
||||||
|
"tr_mtragent_down", "", "mtrregist_rsp", JSONObject.toJSONString(messageVo)
|
||||||
|
);
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error("注册服务器失败:{}",e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* agent更新响应
|
* agent更新响应
|
||||||
@@ -63,6 +136,23 @@ public class MessageHandler {
|
|||||||
*/
|
*/
|
||||||
private void handleAgentUpdateRspMessage(DeviceMessage message) {
|
private void handleAgentUpdateRspMessage(DeviceMessage message) {
|
||||||
List<RspVo> rspVoList = JsonDataParser.parseJsonData(message.getData(), RspVo.class);
|
List<RspVo> rspVoList = JsonDataParser.parseJsonData(message.getData(), RspVo.class);
|
||||||
|
if (!rspVoList.isEmpty()) {
|
||||||
|
RspVo rsp = rspVoList.get(0);
|
||||||
|
if(rsp.getResCode() == 1){
|
||||||
|
RmMtrClientRegistration rmMtrClientRegistration = new RmMtrClientRegistration();
|
||||||
|
rmMtrClientRegistration.setMtrClientId(message.getClientId());
|
||||||
|
rmMtrClientRegistration.setLastUpdateResult("1");
|
||||||
|
rmMtrClientRegistration.setLastUpdateTime(DateUtils.getNowDate());
|
||||||
|
rmMtrClientRegistrationService.updateRmMtrClientRegistration(rmMtrClientRegistration);
|
||||||
|
}else{
|
||||||
|
RmMtrClientRegistration rmMtrClientRegistration = new RmMtrClientRegistration();
|
||||||
|
rmMtrClientRegistration.setMtrClientId(message.getClientId());
|
||||||
|
rmMtrClientRegistration.setDescription(rsp.getResMag());
|
||||||
|
rmMtrClientRegistration.setLastUpdateResult("0");
|
||||||
|
rmMtrClientRegistration.setLastUpdateTime(DateUtils.getNowDate());
|
||||||
|
rmMtrClientRegistrationService.updateRmMtrClientRegistration(rmMtrClientRegistration);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,5 +178,369 @@ public class MessageHandler {
|
|||||||
|
|
||||||
// ========== 具体的消息处理方法 ==========
|
// ========== 具体的消息处理方法 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听心跳
|
||||||
|
* @param message
|
||||||
|
*/
|
||||||
|
private void handleHeartbeatMessage(DeviceMessage message) {
|
||||||
|
List<InitialHeartbeatListen> heartbeats = JsonDataParser.parseJsonData(message.getData(), InitialHeartbeatListen.class);
|
||||||
|
if(!heartbeats.isEmpty()){
|
||||||
|
InitialHeartbeatListen heartbeat = heartbeats.get(0);
|
||||||
|
String clientId = message.getClientId();
|
||||||
|
String version = heartbeat.getVersion();
|
||||||
|
String name = heartbeat.getName();
|
||||||
|
log.debug("处理心跳消息,客户端ID: {}, 时间: {}", clientId, heartbeat.getTimestamp());
|
||||||
|
|
||||||
|
// 使用Redis存储状态
|
||||||
|
String statusKey = HEARTBEAT_STATUS_PREFIX + clientId;
|
||||||
|
String timeKey = HEARTBEAT_TIME_PREFIX + clientId;
|
||||||
|
String recoveryCountKey = HEARTBEAT_RECOVERY_COUNT_PREFIX + clientId;
|
||||||
|
String heartbeatCountKey = HEARTBEAT_COUNT_PREFIX + clientId;
|
||||||
|
String alertKey = HEARTBEAT_ALERT_PREFIX + clientId;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 记录处理前状态(调试用)
|
||||||
|
String prevStatus = redisTemplate.opsForValue().get(statusKey);
|
||||||
|
String prevTime = redisTemplate.opsForValue().get(timeKey);
|
||||||
|
String prevHeartbeatCount = redisTemplate.opsForValue().get(heartbeatCountKey);
|
||||||
|
Boolean prevAlertStatus = redisTemplate.hasKey(alertKey);
|
||||||
|
log.debug("客户端ID: {} 处理前状态 - status: {}, time: {}, heartbeatCount: {}, hasAlert: {}",
|
||||||
|
clientId, prevStatus, prevTime, prevHeartbeatCount, prevAlertStatus);
|
||||||
|
|
||||||
|
// 原子递增心跳计数(线程安全)
|
||||||
|
Long newHeartbeatCount = redisTemplate.opsForValue().increment(heartbeatCountKey);
|
||||||
|
|
||||||
|
// 使用事务更新状态和时间
|
||||||
|
redisTemplate.execute(new SessionCallback<Object>() {
|
||||||
|
@Override
|
||||||
|
public Object execute(RedisOperations operations) throws DataAccessException {
|
||||||
|
operations.multi();
|
||||||
|
// 重置丢失计数为0,设置最后心跳时间
|
||||||
|
operations.opsForValue().set(statusKey, "0");
|
||||||
|
operations.opsForValue().set(timeKey, String.valueOf(System.currentTimeMillis()));
|
||||||
|
return operations.exec();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
log.debug("客户端ID: {} 心跳处理完成,当前心跳次数: {}", clientId, newHeartbeatCount);
|
||||||
|
|
||||||
|
// 检查是否之前有告警状态(心跳恢复检测)
|
||||||
|
if (Boolean.TRUE.equals(redisTemplate.hasKey(alertKey))) {
|
||||||
|
log.info("客户端ID: {} 检测到心跳恢复", clientId);
|
||||||
|
|
||||||
|
// 原子递增恢复计数
|
||||||
|
Long recoveryCount = redisTemplate.opsForValue().increment(recoveryCountKey);
|
||||||
|
|
||||||
|
log.debug("客户端ID: {} 恢复计数: {}", clientId, recoveryCount);
|
||||||
|
|
||||||
|
if (recoveryCount >= 2) {
|
||||||
|
// 达到2次恢复,清除告警状态
|
||||||
|
log.warn("客户端ID: {} 心跳恢复达到{}次,清除告警状态", clientId, recoveryCount);
|
||||||
|
insertHeartbeatLog(clientId, "2", "心跳恢复,设备在线状态改为在线");
|
||||||
|
|
||||||
|
// 清理告警相关key
|
||||||
|
redisTemplate.delete(alertKey);
|
||||||
|
redisTemplate.delete(recoveryCountKey);
|
||||||
|
|
||||||
|
// 修改资源状态为在线
|
||||||
|
updateResourceStatus(clientId, "1");
|
||||||
|
|
||||||
|
log.info("客户端ID: {} 告警状态已清除", clientId);
|
||||||
|
} else {
|
||||||
|
// 未达到2次,只记录恢复次数
|
||||||
|
log.info("客户端ID: {} 心跳恢复第{}次", clientId, recoveryCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只有达到3次心跳才执行数据库操作
|
||||||
|
if (newHeartbeatCount >= 3) {
|
||||||
|
log.info("客户端ID: {} 达到{}次心跳,开始执行数据库操作", clientId, newHeartbeatCount);
|
||||||
|
// agent更新结果存储
|
||||||
|
RmMtrClientRegistration queryMtrClient = new RmMtrClientRegistration();
|
||||||
|
queryMtrClient.setMtrClientId(clientId);
|
||||||
|
List<RmMtrClientRegistration> mtrClientRegistrationList = rmMtrClientRegistrationService.selectRmMtrClientRegistrationList(queryMtrClient);
|
||||||
|
if(mtrClientRegistrationList != null && !mtrClientRegistrationList.isEmpty()){
|
||||||
|
RmMtrClientRegistration rmMtrClientRegistration = mtrClientRegistrationList.get(0);
|
||||||
|
boolean needUpdate = false;
|
||||||
|
RmMtrClientRegistration updateData = new RmMtrClientRegistration();
|
||||||
|
updateData.setId(rmMtrClientRegistration.getId());
|
||||||
|
if(rmMtrClientRegistration.getLogicalNode() == null ||
|
||||||
|
!StringUtils.equals(rmMtrClientRegistration.getLogicalNode(), heartbeat.getLogicalNode())){
|
||||||
|
updateData.setLogicalNode(heartbeat.getLogicalNode());
|
||||||
|
needUpdate = true;
|
||||||
|
}
|
||||||
|
if("0".equals(rmMtrClientRegistration.getOnlineStatus())){
|
||||||
|
updateData.setOnlineStatus("1");
|
||||||
|
needUpdate = true;
|
||||||
|
}
|
||||||
|
if(!StringUtils.equals(rmMtrClientRegistration.getVersion(), version)){
|
||||||
|
updateData.setVersion(version);
|
||||||
|
updateData.setLastUpdateTime(DateUtils.getNowDate());
|
||||||
|
updateData.setLastUpdateResult("1");
|
||||||
|
if(rmMtrClientRegistration.getMethod() == null){
|
||||||
|
updateData.setMethod("0");
|
||||||
|
}
|
||||||
|
needUpdate = true;
|
||||||
|
}
|
||||||
|
if(needUpdate){
|
||||||
|
rmMtrClientRegistrationService.updateRmMtrClientRegistration(updateData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.debug("客户端ID: {} 当前心跳次数: {},未达到3次,跳过数据库操作", clientId, newHeartbeatCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录处理后状态(调试用)
|
||||||
|
String currentStatus = redisTemplate.opsForValue().get(statusKey);
|
||||||
|
String currentTime = redisTemplate.opsForValue().get(timeKey);
|
||||||
|
String currentHeartbeatCount = redisTemplate.opsForValue().get(heartbeatCountKey);
|
||||||
|
Boolean currentAlertStatus = redisTemplate.hasKey(alertKey);
|
||||||
|
log.debug("客户端ID: {} 处理后状态 - status: {}, time: {}, heartbeatCount: {}, hasAlert: {}",
|
||||||
|
clientId, currentStatus, currentTime, currentHeartbeatCount, currentAlertStatus);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理心跳消息异常, clientId: {}", clientId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加一个定时任务方法,定期检查心跳状态
|
||||||
|
@Scheduled(fixedRate = 60000) // 每60s检查一次
|
||||||
|
public void checkHeartbeatStatus() {
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
log.debug("开始心跳状态检查,当前时间: {}", currentTime);
|
||||||
|
|
||||||
|
// 获取所有客户端时间键
|
||||||
|
Set<String> timeKeys = redisTemplate.keys(HEARTBEAT_TIME_PREFIX + "*");
|
||||||
|
if (timeKeys == null) {
|
||||||
|
log.debug("未找到任何心跳时间键");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("找到 {} 个客户端需要检查", timeKeys.size());
|
||||||
|
|
||||||
|
for (String timeKey : timeKeys) {
|
||||||
|
String clientId = timeKey.substring(HEARTBEAT_TIME_PREFIX.length());
|
||||||
|
String statusKey = HEARTBEAT_STATUS_PREFIX + clientId;
|
||||||
|
String alertKey = HEARTBEAT_ALERT_PREFIX + clientId;
|
||||||
|
String heartbeatCountKey = HEARTBEAT_COUNT_PREFIX + clientId;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 检查是否已经存在告警
|
||||||
|
String existingAlert = redisTemplate.opsForValue().get(alertKey);
|
||||||
|
if ("1".equals(existingAlert)) {
|
||||||
|
log.debug("客户端ID: {} 已有告警,跳过检查", clientId);
|
||||||
|
continue; // 如果已有告警,跳过处理
|
||||||
|
}
|
||||||
|
|
||||||
|
String lastTimeStr = redisTemplate.opsForValue().get(timeKey);
|
||||||
|
if (lastTimeStr == null) {
|
||||||
|
log.debug("客户端ID: {} 时间键为空,跳过", clientId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
long lastHeartbeatTime = Long.parseLong(lastTimeStr);
|
||||||
|
long timeDiff = currentTime - lastHeartbeatTime;
|
||||||
|
|
||||||
|
log.debug("客户端ID: {} 最后心跳: {}, 时间差: {}ms, 超时阈值: {}ms",
|
||||||
|
clientId, lastHeartbeatTime, timeDiff, HEARTBEAT_TIMEOUT);
|
||||||
|
|
||||||
|
if (timeDiff > HEARTBEAT_TIMEOUT) {
|
||||||
|
// 心跳超时处理 - 使用原子操作增加计数
|
||||||
|
Long lostCount = redisTemplate.opsForValue().increment(statusKey);
|
||||||
|
if (lostCount == 1) {
|
||||||
|
// 确保第一次增加时值为1
|
||||||
|
redisTemplate.opsForValue().set(statusKey, "1");
|
||||||
|
lostCount = 1L;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.warn("客户端ID: {} 心跳超时,连续次数: {}, 时间差: {}ms",
|
||||||
|
clientId, lostCount, timeDiff);
|
||||||
|
|
||||||
|
if (lostCount >= 3) {
|
||||||
|
log.warn("客户端ID: {} 连续三次心跳丢失,触发告警", clientId);
|
||||||
|
insertHeartbeatLog(clientId, "3", "连续三次心跳丢失");
|
||||||
|
// 告警
|
||||||
|
insertAlarmRecords(clientId);
|
||||||
|
redisTemplate.opsForValue().set(HEARTBEAT_ALERT_PREFIX + clientId, "1");
|
||||||
|
// 设置告警后删除timeKey和statusKey
|
||||||
|
redisTemplate.delete(timeKey);
|
||||||
|
redisTemplate.delete(statusKey);
|
||||||
|
redisTemplate.delete(heartbeatCountKey);
|
||||||
|
|
||||||
|
log.info("客户端ID: {} 已设置告警并清理心跳记录", clientId);
|
||||||
|
// 修改资源状态
|
||||||
|
updateResourceStatus(clientId, "0");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果心跳正常,重置丢失次数
|
||||||
|
String currentStatus = redisTemplate.opsForValue().get(statusKey);
|
||||||
|
if (!"0".equals(currentStatus)) {
|
||||||
|
redisTemplate.opsForValue().set(statusKey, "0");
|
||||||
|
log.debug("客户端ID: {} 心跳正常,重置丢失次数从 {} 到 0", clientId, currentStatus);
|
||||||
|
} else {
|
||||||
|
log.debug("客户端ID: {} 心跳正常,状态已是0", clientId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("检查心跳状态异常, clientId: {}", clientId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("心跳状态检查完成");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新资源状态的公共方法
|
||||||
|
private void updateResourceStatus(String clientId, String status) {
|
||||||
|
log.info("开启更新资源状态========");
|
||||||
|
RmMtrClientRegistration updateData = new RmMtrClientRegistration();
|
||||||
|
updateData.setMtrClientId(clientId);
|
||||||
|
updateData.setOnlineStatus(status);
|
||||||
|
rmMtrClientRegistrationService.updateRmMtrClientRegistration(updateData);
|
||||||
|
}
|
||||||
|
// 插入心跳日志到数据库
|
||||||
|
private void insertHeartbeatLog(String machineId, String status, String remark) {
|
||||||
|
try {
|
||||||
|
InitialHeartbeatListenLog listenLog = new InitialHeartbeatListenLog();
|
||||||
|
listenLog.setClientId(machineId);
|
||||||
|
listenLog.setStatus(status); // 0-离线 1-在线 2-恢复 3-三次丢失
|
||||||
|
listenLog.setRemark(remark);
|
||||||
|
listenLog.setCreateTime(new Date());
|
||||||
|
|
||||||
|
// 调用DAO或Service插入日志
|
||||||
|
initialHeartbeatListenLogService.insertInitialHeartbeatListenLog(listenLog);
|
||||||
|
log.info("已记录心跳日志,客户端ID: {}, 状态: {}", machineId, status);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("插入心跳日志失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加告警日志并推送消息到企业微信
|
||||||
|
* @param clientId
|
||||||
|
*/
|
||||||
|
private void insertAlarmRecords(String clientId) {
|
||||||
|
// 查询clientId是否为交换机唯一标识
|
||||||
|
boolean isSwitch = false;
|
||||||
|
String switchName = "";
|
||||||
|
RmSwitchManagementRemote rmSwitchManagementRemote = new RmSwitchManagementRemote();
|
||||||
|
rmSwitchManagementRemote.setClientId(clientId);
|
||||||
|
R<List<RmSwitchManagementRemote>> rmSwitchManagementRemoteListR = remoteRevenueConfigService.getSwitchNameByClientId(rmSwitchManagementRemote, SecurityConstants.INNER);
|
||||||
|
if (rmSwitchManagementRemoteListR != null &&
|
||||||
|
rmSwitchManagementRemoteListR.getData() != null &&
|
||||||
|
!rmSwitchManagementRemoteListR.getData().isEmpty()) {
|
||||||
|
isSwitch = true;
|
||||||
|
switchName = rmSwitchManagementRemoteListR.getData().get(0).getSwitchName();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建告警日志记录
|
||||||
|
RmAlarmLog rmAlarmLog = createAlarmLog(clientId, isSwitch, switchName);
|
||||||
|
|
||||||
|
// 插入告警日志
|
||||||
|
rmAlarmLogService.insertRmAlarmLog(rmAlarmLog);
|
||||||
|
|
||||||
|
// 发送告警推送
|
||||||
|
sendAlarmPush(rmAlarmLog, isSwitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建告警日志记录
|
||||||
|
*/
|
||||||
|
private RmAlarmLog createAlarmLog(String clientId, boolean isSwitch, String switchName) {
|
||||||
|
RmAlarmLog rmAlarmLog = new RmAlarmLog();
|
||||||
|
String alarmContent = clientId + "下线";
|
||||||
|
|
||||||
|
if (isSwitch) {
|
||||||
|
rmAlarmLog.setClientId(switchName);
|
||||||
|
rmAlarmLog.setAlarmType("2");
|
||||||
|
} else {
|
||||||
|
// 查询管理网公网ip
|
||||||
|
RmNetworkInterface rmNetworkInterface = new RmNetworkInterface();
|
||||||
|
rmNetworkInterface.setClientId(clientId);
|
||||||
|
rmNetworkInterface.setNewFlag(1);
|
||||||
|
List<RmNetworkInterface> interfaceList = rmNetworkInterfaceService.selectRmNetworkInterfaceList(rmNetworkInterface);
|
||||||
|
if (interfaceList != null && !interfaceList.isEmpty()) {
|
||||||
|
interfaceList.stream()
|
||||||
|
.filter(info -> "2".equals(info.getBindIp()) || "3".equals(info.getBindIp()))
|
||||||
|
.findFirst()
|
||||||
|
.ifPresent(networkInterface -> {
|
||||||
|
rmAlarmLog.setMgmPublicIp(networkInterface.getPublicIp());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
rmAlarmLog.setClientId(clientId);
|
||||||
|
rmAlarmLog.setAlarmType("1");
|
||||||
|
}
|
||||||
|
|
||||||
|
rmAlarmLog.setAlarmContent(alarmContent);
|
||||||
|
rmAlarmLog.setAlarmTime(DateUtils.getNowDate());
|
||||||
|
return rmAlarmLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送告警推送
|
||||||
|
*/
|
||||||
|
private void sendAlarmPush(RmAlarmLog rmAlarmLog, boolean isSwitch) {
|
||||||
|
String alarmTypeCode = isSwitch ? AlarmTypeEnum.交换机下线.getCode() : AlarmTypeEnum.服务器下线.getCode();
|
||||||
|
String alarmTypeMsg = isSwitch ? AlarmTypeEnum.交换机下线.getMsg() : AlarmTypeEnum.服务器下线.getMsg();
|
||||||
|
|
||||||
|
RmAlarmPushConfig rmAlarmPushConfig = new RmAlarmPushConfig();
|
||||||
|
rmAlarmPushConfig.setPushMethod(PushMethodEnum.企业微信.getCode());
|
||||||
|
rmAlarmPushConfig.setPushAlarmTypes(alarmTypeCode);
|
||||||
|
List<RmAlarmPushConfig> alarmConfigList = rmAlarmPushConfigService.selectRmAlarmPushConfigList(rmAlarmPushConfig);
|
||||||
|
|
||||||
|
if (alarmConfigList != null && !alarmConfigList.isEmpty()) {
|
||||||
|
for (RmAlarmPushConfig alarmPushConfig : alarmConfigList) {
|
||||||
|
String contentTemplate = alarmPushConfig.getMessageContent();
|
||||||
|
String webhookUrl = alarmPushConfig.getPushAddress();
|
||||||
|
Map<String, Object> alarmMap = new HashMap<>();
|
||||||
|
alarmMap.put("告警时间", rmAlarmLog.getAlarmTime());
|
||||||
|
alarmMap.put("管理网-公网IP", rmAlarmLog.getMgmPublicIp());
|
||||||
|
alarmMap.put("告警类型", alarmTypeMsg);
|
||||||
|
alarmMap.put("告警设备", rmAlarmLog.getClientId());
|
||||||
|
alarmMap.put("告警内容", rmAlarmLog.getAlarmContent());
|
||||||
|
|
||||||
|
if (alarmPushConfig.getContactPhones() != null) {
|
||||||
|
String[] phones = alarmPushConfig.getContactPhones().split(",");
|
||||||
|
WeChatWorkBot.sendTemplateMessage(webhookUrl, contentTemplate, alarmMap, rmAlarmLog.getAlarmContent(), phones, false);
|
||||||
|
} else {
|
||||||
|
WeChatWorkBot.sendTemplateMessage(webhookUrl, contentTemplate, alarmMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存网卡信息
|
||||||
|
* @param message
|
||||||
|
*/
|
||||||
|
private void handleNetWorkDelectMessage(DeviceMessage message) {
|
||||||
|
List<RegisterMsgVo> interfaces = JsonDataParser.parseJsonData(message.getData(), RegisterMsgVo.class);
|
||||||
|
if(!interfaces.isEmpty()) {
|
||||||
|
String mtrClientId = message.getClientId();
|
||||||
|
RegisterMsgVo registerMsg = interfaces.get(0);
|
||||||
|
// 时间戳转换
|
||||||
|
long timestamp = registerMsg.getTimestamp();
|
||||||
|
long millis = timestamp * 1000;
|
||||||
|
Date createTime = new Date(millis / 1000 * 1000); // 去除毫秒
|
||||||
|
List<NetworkInfo> networkInfoList = registerMsg.getNetworkInfo();
|
||||||
|
if(!networkInfoList.isEmpty()){
|
||||||
|
String networkInfo = JSONObject.toJSONString(networkInfoList);
|
||||||
|
// 查询mtrClient信息
|
||||||
|
RmMtrClientRegistration rmMtrClientRegistration = new RmMtrClientRegistration();
|
||||||
|
rmMtrClientRegistration.setMtrClientId(mtrClientId);
|
||||||
|
List<RmMtrClientRegistration> mtrClientRegistrationList = rmMtrClientRegistrationService.selectRmMtrClientRegistrationList(rmMtrClientRegistration);
|
||||||
|
if(mtrClientRegistrationList != null && !mtrClientRegistrationList.isEmpty()){
|
||||||
|
RmMtrClientRegistration mtrClientRegistration = mtrClientRegistrationList.get(0);
|
||||||
|
// 如果网卡信息有变动,更新网卡信息
|
||||||
|
if(!networkInfo.equals(mtrClientRegistration.getNetworkInfo())){
|
||||||
|
RmMtrClientRegistration updateData = new RmMtrClientRegistration();
|
||||||
|
updateData.setId(mtrClientRegistration.getId());
|
||||||
|
updateData.setNetworkInfo(networkInfo);
|
||||||
|
rmMtrClientRegistrationService.updateRmMtrClientRegistration(updateData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user