| @ -1,37 +1,78 @@ | |||||
| package com.inspect.api.service; | package com.inspect.api.service; | ||||
| import com.fasterxml.jackson.core.type.TypeReference; | |||||
| import com.fasterxml.jackson.databind.ObjectMapper; | import com.fasterxml.jackson.databind.ObjectMapper; | ||||
| import com.inspect.api.domain.AlarmMessage; | |||||
| import com.inspect.api.constant.YanyuanConstants; | |||||
| import com.inspect.api.websocket.AlarmWsConnection; | import com.inspect.api.websocket.AlarmWsConnection; | ||||
| import com.inspect.base.core.utils.StringUtils; | |||||
| import com.inspect.base.redis.service.RedisService; | |||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||
| import org.springframework.amqp.core.Message; | |||||
| import org.springframework.amqp.rabbit.annotation.RabbitListener; | import org.springframework.amqp.rabbit.annotation.RabbitListener; | ||||
| import org.springframework.amqp.rabbit.core.RabbitTemplate; | |||||
| import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
| import java.util.Map; | |||||
| @Slf4j | @Slf4j | ||||
| @Component | @Component | ||||
| public class AlarmConsumer { | public class AlarmConsumer { | ||||
| /** 最多重试次数(总尝试次数 = MAX_RETRY + 1) */ | |||||
| private static final int MAX_RETRY = 2; | |||||
| private static final String RETRY_COUNT_HEADER = "alarm-retry-count"; | |||||
| private final AlarmWsConnection wsConnection; | private final AlarmWsConnection wsConnection; | ||||
| private final ObjectMapper objectMapper; | private final ObjectMapper objectMapper; | ||||
| private final RedisService redisService; | |||||
| private final RabbitTemplate rabbitTemplate; | |||||
| public AlarmConsumer(AlarmWsConnection wsConnection, ObjectMapper objectMapper) { | |||||
| public AlarmConsumer(AlarmWsConnection wsConnection, ObjectMapper objectMapper, | |||||
| RedisService redisService, RabbitTemplate rabbitTemplate) { | |||||
| this.wsConnection = wsConnection; | this.wsConnection = wsConnection; | ||||
| this.objectMapper = objectMapper; | this.objectMapper = objectMapper; | ||||
| this.redisService = redisService; | |||||
| this.rabbitTemplate = rabbitTemplate; | |||||
| } | } | ||||
| @RabbitListener(queues = "#{alarmQueue.name}") | @RabbitListener(queues = "#{alarmQueue.name}") | ||||
| public void onAlarm(AlarmMessage msg) { | |||||
| public void onAlarm(Message message) { | |||||
| try { | try { | ||||
| Map<String, Object> msg = objectMapper.readValue(message.getBody(), | |||||
| new TypeReference<Map<String, Object>>() {}); | |||||
| String staticCode = (String) redisService.redisTemplate.opsForValue().get("STATION_CODE"); | |||||
| if (StringUtils.isNotEmpty(staticCode)) { | |||||
| msg.put("stationCode", staticCode); | |||||
| } | |||||
| String json = objectMapper.writeValueAsString(msg); | String json = objectMapper.writeValueAsString(msg); | ||||
| boolean sent = wsConnection.send(json); | boolean sent = wsConnection.send(json); | ||||
| if (sent) { | if (sent) { | ||||
| log.info("Alarm sent to WS: msg={}", msg); | log.info("Alarm sent to WS: msg={}", msg); | ||||
| } else { | } else { | ||||
| log.warn("Alarm not sent, WS not connected: msg={}", msg); | |||||
| throw new RuntimeException("WS not connected, message will be requeued"); | |||||
| retryOrDeadLetter(message); | |||||
| } | } | ||||
| } catch (Exception e) { | } catch (Exception e) { | ||||
| log.error("Alarm consumer error: {}", e.getMessage()); | |||||
| throw new RuntimeException("Alarm processing failed", e); | |||||
| log.error("Alarm consumer error: {}", e.getMessage(), e); | |||||
| retryOrDeadLetter(message); | |||||
| } | } | ||||
| } | } | ||||
| private void retryOrDeadLetter(Message message) { | |||||
| int retryCount = getRetryCount(message); | |||||
| if (retryCount < MAX_RETRY) { | |||||
| message.getMessageProperties().setHeader(RETRY_COUNT_HEADER, retryCount + 1); | |||||
| rabbitTemplate.send(YanyuanConstants.ALARM_RETRY_EXCHANGE, | |||||
| YanyuanConstants.ALARM_RETRY_ROUTING_KEY, message); | |||||
| log.warn("Alarm WS send failed, retry {}/{} scheduled", retryCount + 1, MAX_RETRY); | |||||
| } else { | |||||
| rabbitTemplate.send(YanyuanConstants.ALARM_DEAD_EXCHANGE, | |||||
| YanyuanConstants.ALARM_DEAD_ROUTING_KEY, message); | |||||
| log.error("Alarm WS send failed after {} retries, moved to dead letter queue", MAX_RETRY); | |||||
| } | |||||
| } | |||||
| private int getRetryCount(Message message) { | |||||
| Object count = message.getMessageProperties().getHeader(RETRY_COUNT_HEADER); | |||||
| return count instanceof Number ? ((Number) count).intValue() : 0; | |||||
| } | |||||
| } | } | ||||