Basic.Nack is not processed

Here's what I'm trying to do:

  • Delete message
  • Taking action on a message
  • If the action fails, return the message to the queue
  • If the action is successful, confirm the message

My problem right now is that if the action fails, the message is not reordered, but remains unacknowledged. If I go to the RabbitMQ web config interface, I see the messages are marked as unacknowledged even though the main .Nack has been stepped over.

var delivery = subscription.Next();

var messageBody = delivery.Body;

try
{
   action.Invoke(messageBody);
   subscription.Ack(delivery);
}
catch (Exception ex)
{
   subscription.Model.BasicNack(delivery.DeliveryTag, false, true);
   throw ex;
}

      


Update:

So, I noticed that the messages are coming from Ready to Unrecnowledged very quickly. The speed is faster than I actually call the .Next () caller, as if the .Net client was caching all messages in memory (printing to a stack of memory in my application is actually growing fast) and processes those messages from memory and then sends an Ack ( ), freeing the message from Unrecnowledged.

Update 2:

It looks like the queue was emptied very quickly because I didn't install BasicQos on my model. Everything has been fixed. Basic.Nack () still doesn't work tho:

Model.BasicQos (0, 1, false)

+2


source to share


1 answer


I suspect you are using:
channel.BasicConsume(your_queue_name, false, consumer);

to receive messages.

I ran some tests with RabbitMQ 3.2.4 server and client. I was unable to get either channel.BasickAck(...)

or channel.BasicNack(...)

to work as expected.

However, I was able to get the expected Ack | Nack behavior when I used:
BasicGetResult result = channel.BasicGet(your_queue_name, false);

Thus, you can consider another search method to retrieve messages. I understand that Consume and Dequeue are the "preferred" methods, but they don't work in my case. I needed a fair, one-time confirmation submission. Using BasicGet was the only way to achieve this.

The downside to this approach is that you will lose the client side event iterator that you are using with subscription.Next()

.




If I had to risk a guess, I think something about the local collection of Queue has messed up the channel's ability to provide an acknowledgment. And it's worth noting that creating a user with new QueueingBasicConsumer(channel);

causes a call to prefetch events from the server queue. Consumer Queue is just SharedQueue<RabbitMQ.Client.Events.BasicDeliverEventArgs>

, and SharedQueue is just an extension to IEnumerable.

Also keep in mind that the same channel that pulls the message must provide Ack | Nak. You Can't Ack | Add a message from another channel . Or at least I haven't figured out how to do it and others. This is a problem if you wrap your RabbitMQ objects as instructed (so you don't leave network resources behind ) and you have a lengthy process before you can safely confirm.

This SO answer provides a decent workflow to get around the likely reality that your pull channel won't be the channel that Ack | Nak. The trick sets the TTL and doesn't bother sending the Nack - just let the new message expire and automatically request.

+1


source







All Articles