RabbitMQ PRECONDITION_FAILED - 未知的交付标签

问题描述 投票:0回答:7

我们有一个 PHP 应用程序,可以通过 WebSocket 连接将消息从 RabbitMQ 转发到连接的设备(PHP AMQP pecl 扩展 v1.7.1 和 RabbitMQ 3.6.6)。

消息从队列数组中使用(每个 Websocket 连接 1 个),当我们通过 Websocket 收到消息已收到的确认时,消息会被消费者确认(因此我们可以重新排队未在可接受的时间范围内传递的消息) 。这是以非阻塞方式完成的。

99% 的情况下,这都可以完美运行,但偶尔我们会收到错误“RabbitMQ PRECONDITION_FAILED - 未知的交付标签”。这会关闭通道。据我了解,此异常是由以下条件之一导致的:

  1. 该消息已已经被确认或拒绝。
  2. 尝试通过未传递消息的通道进行确认。
  3. 消息超时 (ttl) 到期后尝试进行确认。

我们已经对上述每一种情况实施了保护,但问题仍然存在。

我意识到有许多实施细节可能会影响这一点,但在概念层面上,是否还有我们尚未考虑且应该处理的其他失败案例?或者有更好的方法来实现上述功能吗?

php rabbitmq amqp
7个回答
50
投票

“PRECONDITION_FAILED - 未知的交付标签”通常是由于双重确认、在错误的通道上确认或确认不应确认的消息而发生。

因此,在同样的情况下,您需要执行

basic.ack
两次或
basic.ack
使用另一个通道


15
投票

(解决方案如下)

引用 Jan Grzegorowski 的博客:

如果您遇到 406 错误消息(包含在 这篇文章的标题您可能有兴趣阅读整个故事。

问题

我使用 amqplib 将基于 NodeJS 的消息处理器与 RabbitMQ 代理。一切似乎都运转良好,但有时 时间 406(预条件失败)消息显示在日志中:

"Error: Channel closed by server: 406 (PRECONDITION-FAILED) with message "PRECONDITION_FAILED - unknown delivery tag 1"

解决方案<--

让事情变得简单:

  • 您必须按照消息到达系统的顺序来确认消息
  • 您不能在与消息到达的通道不同的通道上确认消息。如果您违反任何这些规则,您将面临 406 (前提条件失败)错误消息。

原答案


9
投票

如果您将

Consumer
no-ack 选项设置为
true
,则可能会发生这种情况,这意味着您不能手动调用
ack
函数:

https://www.rabbitmq.com/amqp-0-9-1-reference.html#basic.consume.no-ack

解决方案:

no-ack
标志设置为
false


2
投票

如果您两次知道相同的消息,您可能会遇到此错误。


2
投票

他们上面所说的关于确认两次的内容的变体:
有一种“模糊”的情况,您多次确认一条消息,即当您确认一条消息并将

multiple
参数设置为 true 时,这意味着您尝试确认的所有先前消息都将被确认也是。
因此,如果您尝试通过将 multiple 设置为 true 来确认“自动确认”的消息之一,那么您将尝试多次“确认”它,因此错误会令人困惑,但希望您在阅读几次后能够理解它。


0
投票

确保您拥有正确的应用程序属性:

如果您在没有任何通道配置的情况下使用 RabbitTemplate,请使用“simple”:

spring.rabbitmq.listener.simple.acknowledge-mode=manual

在这种情况下,如果您使用“direct”而不是“simple”,您将收到相同的错误消息。另一种看起来像这样:

spring.rabbitmq.listener.direct.acknowledge-mode=manual

0
投票

我只是忘记在 NACKing 后退出我的回调方法:

if (!hasMatchingSubscriptions(context)) {
    channel.nack(mqMsg, false, false);
    // return; <-- forgot to exit
}
channel.ack(mqMsg);

这导致了 NACK 和 ACK。

© www.soinside.com 2019 - 2024. All rights reserved.