独立处理死信队列消息代理的方法

时间:2019-12-12 16:57:13

标签: java spring spring-cloud-stream messagebroker dead-letter

我有一个项目,当前在下面使用Spring Cloud Streams和RabbitMQ。我已经实现了逻辑based on the documentation。见下文:

@Component
public class ReRouteDlq {

    private static final String ORIGINAL_QUEUE = "so8400in.so8400";

    private static final String DLQ = ORIGINAL_QUEUE + ".dlq";

    private static final String PARKING_LOT = ORIGINAL_QUEUE + ".parkingLot";

    private static final String X_RETRIES_HEADER = "x-retries";

    private static final String X_ORIGINAL_EXCHANGE_HEADER = RepublishMessageRecoverer.X_ORIGINAL_EXCHANGE;

    private static final String X_ORIGINAL_ROUTING_KEY_HEADER = RepublishMessageRecoverer.X_ORIGINAL_ROUTING_KEY;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @RabbitListener(queues = DLQ)
    public void rePublish(Message failedMessage) {
        Map<String, Object> headers = failedMessage.getMessageProperties().getHeaders();
        Integer retriesHeader = (Integer) headers.get(X_RETRIES_HEADER);
        if (retriesHeader == null) {
            retriesHeader = Integer.valueOf(0);
        }
        if (retriesHeader < 3) {
            headers.put(X_RETRIES_HEADER, retriesHeader + 1);
            String exchange = (String) headers.get(X_ORIGINAL_EXCHANGE_HEADER);
            String originalRoutingKey = (String) headers.get(X_ORIGINAL_ROUTING_KEY_HEADER);
            this.rabbitTemplate.send(exchange, originalRoutingKey, failedMessage);
        }
        else {
            this.rabbitTemplate.send(PARKING_LOT, failedMessage);
        }
    }

    @Bean
    public Queue parkingLot() {
        return new Queue(PARKING_LOT);
    }

}

它完成了预期的工作,但是它绑定到RabbitMQ,并且我的公司计划在一两年内停止使用此消息代理(不知道为什么,一定是疯狂的生意)。因此,我想实现同一件事,但将其与任何消息代理分离。

我尝试以这种方式更改rePublish方法,但是它不起作用:

    @StreamListener(Sync.DLQ)
    public void rePublish(Message failedMessage) {
        Map<String, Object> headers = failedMessage.getHeaders();
        Integer retriesHeader = (Integer) headers.get(X_RETRIES_HEADER);
        if (retriesHeader == null) {
            retriesHeader = Integer.valueOf(0);
        }
        if (retriesHeader < 3) {
            headers.put(X_RETRIES_HEADER, retriesHeader + 1);
            String exchange = (String) headers.get(X_ORIGINAL_EXCHANGE_HEADER);
            String originalRoutingKey = (String) headers.get(X_ORIGINAL_ROUTING_KEY_HEADER);
            this.rabbitTemplate.send(exchange, originalRoutingKey, failedMessage);
        }
        else {
            this.rabbitTemplate.send(PARKING_LOT, failedMessage);
        }
    }

由于Message类具有不可变的标头,因此失败-在put尝试抛出无法更改其值的尝试时抛出异常(使用org.springframework.messaging.Message类)。

有没有一种方法可以以独立于消息代理的方式实现此死信队列处理程序?

1 个答案:

答案 0 :(得分:1)

使用

MessageBuilder.fromMessage(message)
    .setHeader("foo", "bar")
     ...
    .build();

请注意,@StreamListener中的消息是春季消息Message<?>,而不是spring-amqp Message,因此不能使用模板发送;您需要输出绑定才能将消息发送到。