Rabbitmq确认消息(Ack)或未确认消息(Nack),将消息留在队列中。

9

我一直在玩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() 来解决了这个问题。 - level_zebra
1
使用Subscription如何“修复”反复遇到相同消息的问题?如果启用了NoAck模式(并且服务器自动ack),或者发送了Ack来确认消息处理操作,两种情况都是错误的,如果无法以某种有效的方式处理消息,但“不应该丢失”。如果不发送Acks,则一旦关闭通道,消息将“重新出现”。我怀疑订阅中的代码只是使用了较大的Prefetch或其他内容..(使用RabbitMQ> 2.7,您可以Nack-requeue以有效地将消息放置在预取缓冲区的“后面”)。 - user2864740
1个回答

18
这是我们公司的做法:如果消息因任何原因而失败,我们会将其nack到一个暂存队列中,等待10秒钟,然后重新放回队列以进行重试。我们最多循环执行此操作10次,如果消息被nack 10次,则我们认为它是一个无法恢复的失败,并将其放入永久死信队列以进行调查。
这是示意图: enter image description here

7
如何将消息“放入等待队列”?这样做是否会自动将其重新排入原始队列中? - Jerald Baker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接