How to requeue a message to the Back of a Rabbit MQ Queue via Spring

Viewed 538

I am writing a SpringBoot RabbitMQ Consumer and I have a need to occasionally re queue a message to the BACK of the queue

I thought this was how negative acknowledgment worked, but basicReject(deliveryTag, true) simply places the message back as close to its original position in the queue as it can, which in my one-at-a-time case is right back at the FRONT of queue.

My first thought was to use a Dead Letter Queue feeding back into the Message Queue on some time interval (similar to the approach mentioned in this answer) but I would rather not create an additional queue if there is some way to simply re queue to the BACK of the initial queue

My below structure simply consumes the message and fails to re-add it to the queue.

How can this be accomplished without a DLQ?

@ServiceActivator(inputChannel = "amqpInputChannel")
    public void handle(@Payload String message,
                       @Header(AmqpHeaders.CHANNEL) Channel channel,
                       @Header(AmqpHeaders.DELIVERY_TAG) Long deliveryTag){

    try{

        methodThatThrowsRequeueError();
        methodThatThrowsMoveToErrorQueueError();

    } catch (RequeueError re) {

        channel.basicAck(deliveryTag, false);
        sendMessageToBackOfQueue(message);
        return;

    } catch (MoveToErrorQueueError me) {
        //Structured the same as sendMessageToBackOfQueue, works fine
        moveMessageToErrorQueue(message);
    }
    
    channel.basicAck(deliveryTag, false);
}

private void sendMessageToBackOfQueue(String message) {
        try {
            rabbitTemplate.convertAndSend(
                exchangeName,
                routingKeyRequeueMessage,
                message,
                message -> {
                    message.getMessageProperties().setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN);
                    return message;
                }
            );
        } catch (AmqpException amqpEx) {
            //error handling which is not triggered...
        }
    }

1 Answers

TL;DR : There is no way I have found to forward a Message from a listening Service back into the originating Queue with no intermediary.

There are several options that revolve around Dead Letter Queues/Dead Letter Exchanges, but a non-DLQ/DLX solution we found was a timed Exchange, a psuedo DLX if you will. Essentially:

Message enters MessageExchange (MsgX), which propagates to the Service Queue (SvcQ). The Service (Svc) Gets a Message from the SvcQ.

Once you have determined that the message should be sent to the back of the SvcQ, Svc should:

  1. Send an Acknowledgement to SvcQ.
  2. Send the message to another exchange, our timed psuedo-DLX
  3. The psuedo-DLX can be configured to release messages to the (BACK OF!!) SvcQ on some timed interval
Related