简体   繁体   English

基本.Nack未处理

[英]basic.Nack not being processed

Here is what I am trying to do: 这是我正在尝试做的事情:

  1. Dequeue a message 出消息
  2. Do an action with the message 对消息进行操作
  3. If the action fails, put the message back in the queue 如果操作失败,则将消息放回队列
  4. If the action succeeds, acknowledge the message 如果操作成功,请确认消息

My problem right now is that, if the action fails, the message isn't re-queued, but stays unacknowledged. 我现在的问题是,如果操作失败,则不会重新排队该消息,而是保持未确认状态。 If I go in RabbitMQ web configuration interface, I see that the messages are flagged as unacknowledged, even though the basic.Nack has been stepped over. 如果我进入RabbitMQ Web配置界面,即使basic.Nack已被跳过,我也会看到消息被标记为未确认。

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've noticed that Messages go from Ready to Unacknowledged really fast. 因此,我注意到消息从“就绪”变为“未确认”的速度非常快。 A rate way faster then I'm actually calling subscriber.Next(), as if the the .Net client caches all the messages in memory (the memory foot print of my app is actually growing quite fast), and processes those messages from memory and sends the Ack() afterwards, unflagging the message from Unacknowledged. 比我实际上打电话给Subscriber.Next()的速度要快得多,就好像.Net客户端将所有消息缓存在内存中(我的应用程序的内存占用量实际上增长得非常快),并从内存中处理这些消息并随后发送Ack(),取消标记来自未确认的消息。

Update 2: 更新2:

Seems like the queue being emptied really fast was because I hadn't set BasicQos on my Model. 好像排空队列真的很快,是因为我没有在Model上设置BasicQos。 The following fixed everything. 以下内容修复了所有问题。 Basic.Nack() still doesn't seem to work tho: Basic.Nack()似乎仍然无法工作:

Model.BasicQos(0, 1, false) Model.BasicQos(0,1,假)

I suspect you're using: 我怀疑您正在使用:
channel.BasicConsume(your_queue_name, false, consumer); to retrieve messages. 检索消息。

I ran several tests with a RabbitMQ 3.2.4 server and client. 我使用RabbitMQ 3.2.4服务器和客户端运行了多个测试。 I was unable to get either channel.BasickAck(...) or channel.BasicNack(...) to work as expected. 我无法使channel.BasickAck(...)channel.BasicNack(...)都能按预期工作。

That said, I was able to get the expected Ack | 也就是说,我能够获得预期的Ack | Nack behavior when I used: 使用时出现小问题:
BasicGetResult result = channel.BasicGet(your_queue_name, false);

So you may want to consider a different retrieval method to get messages. 因此,您可能需要考虑使用其他检索方法来获取消息。 I realize that the Consume & Dequeue are the "preferred" methods but they weren't working in my case. 我认识到Consume&Dequeue是“首选”方法,但在我的情况下它们不起作用。 I wanted fair, one-at-a-time dispatch with acknowledgments. 我想一次公平的,一次确认的派遣。 Using BasicGet was the only way I could achieve that. 使用BasicGet是实现此目标的唯一方法。

The downside to that approach is you'll possibly lose the client side event iterator you're using with subscription.Next() . 这种方法的缺点是,您可能会失去与subscription.Next()一起使用的客户端事件迭代器。


If I had to venture a guess, I think that something about the local Queue collection is messing up the channel's ability to provide an acknowledgement. 如果我不得不大胆猜测,我认为有关本地Queue集合的某些事情会破坏该通道提供确认的能力。 And it's worth pointing out that creating the consumer with new QueueingBasicConsumer(channel); 值得指出的是,使用new QueueingBasicConsumer(channel);创建使用者new QueueingBasicConsumer(channel); triggers a call to pre-fetch events from the server's queue. 触发调用以从服务器队列中预提取事件。 The consumer's Queue is just a SharedQueue<RabbitMQ.Client.Events.BasicDeliverEventArgs> and SharedQueue is just an extension of IEnumerable. 使用者的队列只是SharedQueue<RabbitMQ.Client.Events.BasicDeliverEventArgs>而SharedQueue只是IEnumerable的扩展。

Also keep in mind that the same channel that pulls the message needs to provide the Ack | 还请记住,提取消息的相同通道也需要提供Ack | Nack. NACK。 You cannot Ack | 您不能确认| Nack a message from a different channel . 取消来自其他渠道的消息 Or at least I haven't figured out how to do so, nor have others. 或者至少我还没有弄清楚该怎么做,也没有其他人。 That's a problem if you wrap your RabbitMQ objects within using statements (so you don't leave network resources laying around) and you have long process to run before you can safely acknowledge. 这是一个问题,如果您将RabbitMQ对象包装在using语句中(这样就不会留下网络资源), 并且您需要经过很长的流程才能安全地进行确认。

This SO Answer lays out a decent workflow to get around the likely reality that your pulling channel is not going to be the channel that sends the Ack | 该《 解答》列出了一个体面的工作流程,以解决可能的现实情况,即您的提货渠道将不再是发送Ack的渠道。 Nack. NACK。 The trick is setting a TTL and not bothering with sending a Nack - just let the new message expire and requeue automatically. 诀窍是设置TTL,而不会打扰发送Nack-只让新消息过期并自动重新排队。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM