简体   繁体   English

如何使用反应堆 rabbitmq 处理死信队列

[英]How to work with Dead letter queues with reactor rabbitmq

In our application we are moving from spring-amqp to reactor-rabbitmq to work well with reactive nature of the application.在我们的应用程序中,我们正在从 spring-amqp 迁移到 reactor-rabbitmq,以便与应用程序的反应性质良好配合。 We have been reading the official guide from project reactor.我们一直在阅读 project reactor 的官方指南 However I am not quite sure, how to send the messages to dead-letter queues once the retries are exhausted.但是我不太确定,一旦重试用尽,如何将消息发送到死信队列。

In the previous implementation we are throwing Spring-AMPQ provided AmqpRejectAndDontRequeueException , which causes the messages to go to dead-letter queue automatically, without using a dedicated publisher to the dead letter queue.在之前的实现中,我们抛出 Spring-AMPQ 提供的AmqpRejectAndDontRequeueException ,这会导致发送到 go 的消息自动进入死信队列,而不使用死信队列的专用发布者。 How to do similar in reactor-rabbitmq?如何在 reactor-rabbitmq 中做类似的事情? Do I need to write a dedicated publisher which gets called from the listeners after the retries are exhausted or there are other ways to handle it.我是否需要编写一个专用的发布者,在重试用尽后从侦听器中调用它,或者有其他方法来处理它。 Also, is there an official project reactor documentation for DLQs and parking queues.此外,是否有用于 DLQ 和停车队列的官方项目反应器文档。

Here is some code samples for both versions:以下是两个版本的一些代码示例:

AMQP Version: AMQP 版本:

@AllArgsConstructor
public class SampleListener {
    private static final Logger logger = LoggerFactory.getLogger(SampleListener.class);
    private final MessageListenerContainerFactory messageListenerContainerFactory;
    private final Jackson2JsonMessageConverter converter;

    @PostConstruct
    public void subscribe() {
        var mlc = messageListenerContainerFactory
                .createMessageListenerContainer(SAMPLE_QUEUE);
        MessageListener messageListener = message -> {
            try {
                TraceableMessage traceableMessage = (TraceableMessage) converter.fromMessage(message);
                ObjectMapper mapper = new ObjectMapper();
                mapper.registerModule(new JavaTimeModule());
                MyModel myModel = mapper.convertValue(traceableMessage.getMessage(), MyModel.class);
                MDC.put(CORRELATION_ID, traceableMessage.getCorrelationId());
                logger.info("Received message for id : {}", myModel.getId());
                processMessage(myModel)
                        .subscriberContext(ctx -> {
                            Optional<String> correlationId = Optional.ofNullable(MDC.get(CORRELATION_ID));
                            return correlationId.map(id -> ctx.put(CORRELATION_ID, id))
                                    .orElseGet(() -> ctx.put(CORRELATION_ID, UUID.randomUUID().toString()));
                        }).block();
                MDC.clear();
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                throw new AmqpRejectAndDontRequeueException(e.getMessage(), e);
            }
        };
        mlc.setupMessageListener(messageListener);
        mlc.start();
    }

processMessage is doing the business logic, and in case if it fails I want to move it to DLQ. processMessage正在执行业务逻辑,如果失败,我想将其移至 DLQ。 Works fine in case of AMQP.在 AMQP 的情况下工作正常。

Reactor RabbitMQ version:电抗器 RabbitMQ 版本:

@AllArgsConstructor
public class SampleListener {
    private static final Logger logger = LoggerFactory.getLogger(SampleListener.class);
    private final MessageListenerContainerFactory messageListenerContainerFactory;
    private final Jackson2JsonMessageConverter converter;

    @PostConstruct
    public void subscribe() {
        receiver.consumeAutoAck(SAMPLE_QUEUE)
                .subscribe(delivery -> {
                            TraceableMessage traceableMessage = Serializer.to(delivery.getBody(), TraceableMessage.class);
                            Mono.just(traceableMessage)
                                    .map(this::extractMyModel)
                                    .doOnNext(myModel -> logger.info("Received message for id : {}", myModel.getId()))
                                    .flatMap(this::processMessage)
                                    .doFinally(signalType -> MDC.clear())
                                    .retryWhen(Retry
                                            .fixedDelay(1, Duration.ofMillis(10000))
                                            .onRetryExhaustedThrow() //Move to DLQ
                                            .doAfterRetry(retrySignal -> {
                                                if ((retrySignal.totalRetries() + 1) >= 1) {
                                                    logger.info("Exhausted retries");
                                                    //Move to DLQ
                                                }
                                            }))
                                    .subscriberContext(ctx -> ctx.put(CORRELATION_ID, traceableMessage.getCorrelationId()))
                                    .subscribe();
                        }
                );

    }

One of those two places with comment //Move to DLQ , would be I am guessing where the message should go to DLQ.有评论的那两个地方之一//Move to DLQ ,我猜消息应该 go 到 DLQ 的位置。 That's where I decide I cannot process this anymore.这就是我决定我不能再处理这个的地方。 Should there be a different publisher pushing to DLQ or any specific setting can take care of it automatically.如果有不同的发布者推送到 DLQ 或任何特定设置可以自动处理它。

Please let me know.请告诉我。

I got the answer to this problem.我得到了这个问题的答案。 I was using async listeners and using the consumeAutoAck .我正在使用异步侦听器并使用consumeAutoAck When I switched to consumeManualAck I get a AcknowledgebleDelivery where I can do a nack(false) which is supposed to move it to dead letter queue.当我切换到consumeManualAck时,我得到一个AcknowledgebleDelivery ,我可以在其中执行一个nack(false) ,它应该将它移动到死信队列。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM