Skip to content
Advertisement

Rabbit MQ doesn’t flush acks?

The problem appeared in logs: Consumer failed to start in 60000 milliseconds; does the task executor have enough threads to support the container concurrency?

We try to open handlers for like 50 queues dynamically by SimpleMessageListenerContainer.addQueueNames(), then application is started. It consumes some messages, but the RabbitMQ admin panel shows that they are unacked. After a significant amount of time, messages are stacking up to 6 unacked messages (queue has fairly low amount of messages per minute) per queue, which sums up to 300 messages total, something happens and they all become consumed and acked. While messages are unacked, the container seems to be trying to load another consumer until it bumps into the limit.

We rely on AUTO acknowledgment mode now, when it was MANUAL, it was fine.

There are two questions:

  1. What can be the reason for unacked messages? Is there any flushing mechanism that doesn’t trigger often?

  2. What do I do with “not enough threads” message?

Those two seem to be really related one to another.

Here’s the setup:

JavaScript

Advertisement

Answer

Okay, I figured out what the problem was. Basically, it couldn’t start all of the queues consumers in time, since it not only is slow process for too slow for SimpleMessageListenerContainer, but also we tried to addQueueNames one by one.

JavaScript

But the following line of documentation for SimpleMessageListenerContainer remained unnoticed:

JavaScript

Which means what actually happened is recreation of (1, 2, … N) consumers. What made it even worse is that if the request comes from the API, we did exactly the same simpleContainerListener.addQueueNames(queueName) after handling the request, which recreated all of consumers after that.

Also, recreation of the consumers was the reason why AUTO acknowledgement didn’t work: threads were hanging trying to build enough consumers before the timeout.

I fixed this by adding DirectMessageListenerContainer to handle recently added queues, which is blazing fast, compared to SimpleMessageListenerContainer for the particular case of adding just one new consumer.

JavaScript

The downside is DirectMessageListenerContainer using 1 thread per queue on every instance. This is exactly why I didn’t want to use it in the first place, but using both DirectMessageListenerContainer for recent and SimpleContainerListener for already existing queues significantly reduces amount of thread required to handle those queues. As far as I understand, an overwhelming usage of DirectMessageListenerContainer will lead to OOM eventually, so the next step can be to transfer queues from direct to simple container listener in batches.

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement