acking RabbitMQ 消息是否有超时?

Is there a timeout for acking RabbitMQ messages?

我想设置一个超时时间,在该超时时间之后,出列的消息会自动 NACK。

当我将消息出列时,我会等待它通过套接字传输并且另一方确认接收。

我是否需要保留一个计时器列表,或者 RMQ 可以自动处理吗?

private void Run()
{
    _rmqConnection = _queueConnectionFactory.CreateFactory().CreateConnection();

    _rmqReadchannel = _rmqConnection.CreateModel();

    _rmqReadchannel.QueueDeclare(QueueIdOutgoing(), true, false, false, null);

    _rmqReadchannel.BasicQos(0, 1, false);
    var consumer = new QueueingBasicConsumer(_rmqReadchannel);
    _rmqReadchannel.BasicConsume(QueueIdOutgoing(), false, consumer);
    while (true)
    {
        if (!_rmqReadchannel.IsOpen)
        {
            throw new Exception("Channel is closed");
        }
        var ea = consumer.Queue.Dequeue();
        string jsonData = Encoding.UTF8.GetString(ea.Body);
        if (OnOutgoingMessageReady != null)
        {
            OnOutgoingMessageReady(this, new QueueDataEventArgs(jsonData, ea.DeliveryTag));
        }
        //waiting for ACK from a different thread
    }
}

是的。这在 official Python tutorial:

中讨论

A timeout (30 minutes by default) is enforced on consumer delivery acknowledgement. This helps detect buggy (stuck) consumers that never acknowledge deliveries.

您可以在 Delivery Acknowledgement Timeout

的 RabbitMQ 文档中找到更多信息

然而,情况并非总是如此。旧版本的 RabbitMQ(至少到版本 3.6.x)没有提供任何类型的超时机制来确认消息。 older versions of the official Python tutorial:

中提到了这一点

There aren't any message timeouts; RabbitMQ will redeliver the message only when the worker connection dies. It's fine even if processing a message takes a very, very long time.

Section 3.1.8 of the AMQP 0-9-1 specification 描述了 Acknowledgements,并且非常清楚它们可以是 Automatic(客户端不需要做任何事情,消息一旦被确认它们已交付)或 Explicit(客户端必须对其已处理的每条消息或每组消息进行确认)。

这是 2009 年的一些 past discussion 证实了这种行为。

我能看到的关于更改此行为的第一个参考是 this PR from April 2019. I'm not sure what version of the server that change was included in, but it sounds like the default was initially "no timeout", then 15 minutes in RabbitMQ 3.8.15, then 30 minutes in RabbitMQ 3.8.17(截至 2021 年 10 月它仍然存在)。

因此:此行为取决于您的 RabbitMQ 版本。旧版本要求您在一段时间后明确发送 NACK。较新的版本有默认超时。

现代版本的 RabbitMQ 有 ack timeout。 因此,如果您的消费者在交付确认之前花费大量时间,请谨慎更新新版本。

If a consumer does not ack its delivery for more than the timeout value (30 minutes by default), its channel will be closed with a PRECONDITION_FAILED channel exception.