My Java application sends messages to RabbitMQ exchange, then exchange redirects messages to binded queue. I use Springframework AMQP java plugin with RabbitMQ.
The problem: message comes to queue, but it stays in "Unacknowledged" state, it never becomes "Ready".
What could be the reason?
RabbitMQ Unacked Messages are the messages that are not Acknowledged. If a consumer fails to acknowledge messages, the RabbitMQ will keep sending new messages until the prefetch value set for the associated channel is equal to the number of RabbitMQ Unacked Messages count.
Check if there are unacked messages. If a consumer fails to ack messages, RabbitMQ will stop delivering new messages to it once the unacked message counts equals the prefetch value set for the associated channel.
RabbitMQ Durable queues are those that can withstand a RabbitMQ restart. If a queue is not durable, all messages will be lost if RabbitMQ is shut down for any reason. For messages to survive restarts, both of these configurations must be true.
In standard queues, messages are retained for at least 72 hours and will be deleted 72 hours later.
An Unacknowledged message implies that it has been read by your consumer, but the consumer has never sent back an ACK to the RabbitMQ broker to say that it has finished processing it.
I'm not overly familiar with the Spring Framework plugin, but somewhere (for your consumer) you will be declaring your queue, it might look something like this (taken from http://www.rabbitmq.com/tutorials/tutorial-two-java.html):
channel.queueDeclare(queueName, ....)
then you will setup your consumer
bool ackMode = false; QueueingConsumer consumer = new QueueingConsumer(channel); channel.basicConsume(queueName, ackMode, consumer);
ackMode above is a boolean, by setting it to false, we're explicitly saying to RabbitMQ that my consumer will acknowledge each message it is given. If this flag was set to true, then you wouldn't be seeing the Unacknowledged count in RabbitMQ, rather as soon as a consumer has read the message off (i.e it has been delivered to the consumer it will remove it from the queue).
To acknowledge a message you would do something like this:
QueueingConsumer.Delivery delivery = consumer.nextDelivery(); //...do something with the message... channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false); //the false flag is to do with multiple message acknowledgement
If you can post some of your consumer code then I might be able to help further...but in the mean time take a look at BlockingQueueConsumer specifically: the constructor you will see that you can set the AcknowledgeMode and also take a look at the nextMessage() this will return a Message object which contains a method called getDeliveryTag() this will return a Long which is the ID that you would send back on the basicAck
Just to add my 2 cents for another possible reason for messages staying in an unacknowledged state, even though the consumer makes sure to use the basicAck method-
Sometimes multiple instances of a process with an open RabbitMQ connection stay running, one of which may cause a message to get stuck in an unacknowledged state, preventing another instance of the consumer to ever refetch this message.
You can access the RabbitMQ management console (for a local machine this should be available at localhost:15672), and check whether multiple instances get hold of the channel, or if only a single instance is currently active:
Find the redundant running task (in this case - java) and terminate it. After removing the rogue process, you should see the message jumps to Ready state again.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With