问题
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
回答1:
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).
回答2:
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
来源:https://stackoverflow.com/questions/7849891/rabbitmq-basic-get-and-acknowledgement