Search code examples
rabbitmqspring-integrationspring-cloud-streamspring-rabbit

Publisher Confirms gives ACK when message can not be routed by RabbitMQ


I'm doing a small project to check how works Publisher Confirms for RabbitMQ with Spring Cloud Stream 3.0.1.

I have a particular case when a message is send to the exchange of RabbitMQ, but this exchange can not route this message. I expected that this message will be handled by the Publisher as an error but my surprise was that this is handled as an ACK.

This is the code of the Publisher:

@Slf4j
@Timed
@Component
@RequiredArgsConstructor
public class TestPublisher {

    private final MessagingChannels messagingChannels;

    public boolean send(Message<Event<TestEvent>> message) {

        log.info("Message for Testing Publisher confirms sent: " + message);
        return messagingChannels.walletTest().send(message);
    }

    @ServiceActivator(inputChannel = TEST_ACK)
    public void acks(Message<?> ack) {
        log.info("Message ACK received for Test: " + ack);
    }

    @ServiceActivator(inputChannel = TEST_ERROR)
    public void errors(Message<?> error) {
        log.info("Message error for Test received: " + error);
    }
}

I can see this message printed in the log of org.springframework.integration.handler.LoggingHandler

org.springframework.integration.amqp.support.ReturnedAmqpMessageException, failedMessage=GenericMessage [payload=byte[1009], headers={id=c9bc65bc-9256-1ce2-324f-167cc526a819, timestamp=1591962425292}] [amqpMessage=(Body:'{"payload":{"id":"f696668d-140e-4ba7-96c7-ea6decdfcccd","version":20000,"currency":"USD"},"eventName":"TEST_UPDATED",......contentType=application/json, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, deliveryTag=0]), replyCode=312, replyText=NO_ROUTE, .....]

As you can see, it is reported as a failure message with replyCode=312 and replyText=NO_ROUTE.

However, it is received as an ACK instead of NACK. I have checked a bit in the documentation and I think this the expected behaviour with Publisher Confirms enabled, but I would like to confirm that. And if it's the case, is there some way to detect in the context of the ACK that this message could not berouted? Because inside this context, I don't have the replyCode and the replyText, I have only the proper message sent by the Publisher.

Publisher confirms is activated properly with the next properties:

spring:
  rabbitmq:
    publisher-confirm-type: correlated
    publisher-returns: true

ACK Channel and errors are correctly configured with errorChannelEnabled and confirmAckChannel properties.


Solution

  • That is how it works, the ack, not a nack, is sent after the returned message.

    See the documentation.

    For unroutable messages, the broker will issue a confirm once the exchange verifies a message won't route to any queue (returns an empty list of queues). If the message is also published as mandatory, the basic.return is sent to the client before basic.ack.

    You cannot tell that is was returned in the context of the ack.

    You can, if you use Spring AMQP directly rather than via Spring Cloud Stream because the ack callback gets CorrelationData which will containe the returned message.