28

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?

sunny
  • 1,887
  • 3
  • 29
  • 40

2 Answers2

29

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:

RabbitMQ Connections

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.

Shlomi Uziel
  • 868
  • 7
  • 15
  • 1
    This answer is just amazing. I was stuck on this without knowing the reason why few minutes ago my messages were being delivered flawlessly and then why they werent after i restarted my mac. Do you know why that would happed? – Arun T Dec 06 '18 at 10:46
  • Just want to add to the above, this is what happened to me. I tried to view messages in a queue from the management console, and for some reason the page never loaded and the messages were stuck in unacknowledged. I hoped they would just time out overnight, but they didn't. The above advice lead me to find an open connection with my user. As soon as i forced that closed, the messages all went back to ready. Thankfully these messages were unimportant so the delay doesn't matter. However, recovering from this is valuable information to know. – Piercy Oct 23 '19 at 08:33
  • 1
    This appears to be the case for me as well, however I do not understand why. I have two separate connections one for Publisher and one for Consumer. When I close the Consumer connection and the connection is re-established, the message is delivered. This makes little sense to me right now since I'd expect long running connections to work. I know I'm missing some configuration somewhere, just not sure what yet. – O.MeeKoh May 27 '22 at 20:22
28

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

kzhen
  • 3,020
  • 19
  • 21