| @ -1,37 +1,78 @@ | |||
| package com.inspect.api.service; | |||
| import com.fasterxml.jackson.core.type.TypeReference; | |||
| 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.base.core.utils.StringUtils; | |||
| import com.inspect.base.redis.service.RedisService; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| import org.springframework.amqp.core.Message; | |||
| import org.springframework.amqp.rabbit.annotation.RabbitListener; | |||
| import org.springframework.amqp.rabbit.core.RabbitTemplate; | |||
| import org.springframework.stereotype.Component; | |||
| import java.util.Map; | |||
| @Slf4j | |||
| @Component | |||
| 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 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.objectMapper = objectMapper; | |||
| this.redisService = redisService; | |||
| this.rabbitTemplate = rabbitTemplate; | |||
| } | |||
| @RabbitListener(queues = "#{alarmQueue.name}") | |||
| public void onAlarm(AlarmMessage msg) { | |||
| public void onAlarm(Message message) { | |||
| 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); | |||
| boolean sent = wsConnection.send(json); | |||
| if (sent) { | |||
| log.info("Alarm sent to WS: msg={}", msg); | |||
| } 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) { | |||
| 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; | |||
| } | |||
| } | |||