Rabbitmq Ack 或 Nack,将消息留在队列中

Posted

技术标签:

【中文标题】Rabbitmq Ack 或 Nack,将消息留在队列中【英文标题】:Rabbitmq Ack or Nack, leaving messages on the queue 【发布时间】:2015-04-20 16:15:01 【问题描述】:

我一直在玩 RabbitMq.net 和消息确认。 如果消费者能够处理消息,您可以以

的形式发回 ack
channel.BasicAck(ea.DeliveryTag, false);

这会将它从队列中移除。

但是如果消息无法处理怎么办?可能是临时中断,您不希望将消息从队列中删除,然后将其放在后面并继续下一条消息?

我尝试过使用

channel.BasicNack(ea.DeliveryTag, false, true);

但下一轮它仍然收到相同的消息,而不是移动到队列中的下一条消息

我的完整代码是

class Program

    private static IModel channel;
    private static QueueingBasicConsumer consumer;
    private static IConnection Connection;

    static void Main(string[] args)
    
        Connection = GetRabbitMqConnection();
        channel = Connection.CreateModel();
        channel.BasicQos(0, 1, false);
        consumer = new QueueingBasicConsumer(channel);
        channel.BasicConsume("SMSQueue", false, consumer);
        while (true)
        
            if (!channel.IsOpen)
            
                throw new Exception("Channel is closed");
            
            var ea = consumer.Queue.Dequeue();
            string jsonified = Encoding.UTF8.GetString(ea.Body);
            var message = JsonConvert.DeserializeObject<SmsRecords>(jsonified);
            if (ProcessMessage())
                channel.BasicAck(ea.DeliveryTag, false);
            else
                channel.BasicNack(ea.DeliveryTag, false, true);
        
    

    private static bool ProcessMessage()
    
        return false;
    

    public static IConnection GetRabbitMqConnection()
    
        try
        
            var connectionFactory = new ConnectionFactory
            
                UserName = "guest",
                Password = "guest",
                HostName = "localhost"
            ;
            return connectionFactory.CreateConnection();
        
        catch (Exception ex)
        
            Console.WriteLine(ex.Message);
            return null;
        
    

【问题讨论】:

我通过订阅解决了这个问题,然后调用 BasicDeliverEventArgs basicDeliveryEventArgs = subscription.Next(); 如何使用订阅“解决”不断遇到相同消息的问题? NoAck 模式打开(并且服务器自动确认)或发送 Ack 以确认消息的处理 - 如果消息无法以某种有效方式处理但“不应丢失”,则两者都是错误的。如果没有发送 Acks,那么一旦通道关闭,消息就会“重新出现”。我怀疑带有 Subscription 的代码只是使用了更大的 Prefetch 或其他东西..(使用 RabbitMQ > 2.7,您可以 Nack-requeue 有效地将消息“放到”预取缓冲区的“后面”)。 【参考方案1】:

这就是我公司的做法:如果一条消息失败(出于任何原因),我们将消息放入一个等待队列中等待 10 秒,然后将其放回队列中进行重试。我们最多循环 10 次,如果消息被 nack 10 次,那么我们认为这是一个我们无法恢复的失败,我们将它放入一个永久的死信队列进行调查。

图表如下:

【讨论】:

如何将消息“放入等待队列”?它不会自动在原始队列中重新排队吗?

以上是关于Rabbitmq Ack 或 Nack,将消息留在队列中的主要内容,如果未能解决你的问题,请参考以下文章

如何强制 RabbitMQ 代理 NACK 测试消息?

RabbitMQ的死信队列

rabbitmq消费端的nack和重回队列的总结

RabbitMQ 上的 Nack 和拒绝

pubsub 流式处理 pull nack 与无确认行为

RabbitMQ中的SimpleMessageListener