I'm invoking:
GetResponse response = channel.basicGet("some.queue", false); // no auto-ack
....
channel.basicAck(deliveryTag, ...);
However, when I invoke basicGet
, the messages in the queue stay in "Ready", rather than in "Unacknowledged". I want them to be in unacknowledged, so that I can either basic.ack
them (thus discarding them from the queue), or basic.nack
them
I'm doing the following to mimic Delaying the ack:
At consumption time
- Get(consume) the message form the initial Queue.
- Create a "PendingAck_123456" Queue.
123456 is a unique id of the message.
Set the following properties
- x-message-ttl (to requeue after
timeout)
- x-expires (to make sure the temp queue will be deleted)
- x-dead-letter-exchange and x-deal-letter-routing-key to requeue to
the initial Queue upon TTL expiration.
- Publish the message Pending ack to this "PendingAck_123456" Queue
- Ack the message to delete it from the initial queue
At Acknowledge time
- Calculate Queue Name from Message Id and Get from the "PendingAck_123456" Queue
- Acknowledge it (no need to call
.getBody()
).
That'll delete it from this pending queue, preventing the TTL to requeue it
Remarks
- A Queue for only 1 message.. Is that an issue if there are a lot of such Queues ?
- A requeued message will be sent at the queue input side.. not at the queue output (as would do a real ack).. There is an impact on the messages order.
- Message is copied by the application to the Pending Queue.. This is an additional step that may have impacts on the overall performance.
- To mimic a Nack/Reject, you you may want to Copy the message to the Initial Queue, and Ack it from the PendingAck queue. By default, the TTL would do it (later).
When doing ack
immediately after the get
it works fine. However, in my case, they were separated by a request. And spring's template closes the channel and connection on each execution. So there are three options:
- keep one channel and connection open throughout the whole lifetime of the application
- have some kind of conversation-scope (or worst-case: use the session) to store the same channel and reuse it.
- use one channel per request, acknowledge receipt immediately, and store the messages in memory.
In the former two cases you can't do it with spring's RabbitTemplate