RabbitMQ PRECONDITION_FAILED - 未知的传递标签

29
我们有一个PHP应用程序,它通过WebSocket连接(PHP AMQP pecl extension v1.7.1和RabbitMQ 3.6.6)将消息从RabbitMQ转发到连接的设备。
消息从一组队列(每个WebSocket连接1个)中消耗,并在我们通过WebSocket接收到确认消息已被接收时由使用者进行确认(因此,我们可以重新排队在可接受的时间内未传递的消息)。这是以非阻塞方式完成的。
99%的时间,这种方法完美地运行,但很少出现错误“RabbitMQ PRECONDITION_FAILED - unknown delivery tag”,这会关闭通道。据我理解,此异常是以下条件之一的结果:
1. 消息已经被确认或拒绝。 2. 在不传递消息的情况下尝试在通道上进行确认。 3. 在消息超时(ttl)后尝试确认。
我们已为上述每种情况实施了保护措施,但问题仍然存在。
我意识到有许多可能影响此问题的实现细节,但是在概念层面上,是否还有我们没有考虑并且应该处理的其他故障情况?或者是否有更好的方法来实现上述功能?
6个回答

48

"前置条件失败 - 未知的传递标签"通常是由于双重确认、在错误的通道上进行确认或确认不应该确认的消息而发生。

因此,在某些情况下,您正在尝试执行两次basic.ack或使用另一个通道执行basic.ack


3
正如@DenisKolodin所回答的,我认为首先我们应该检查auto_ack是否被设置为False。如果是True,那么手动确认时就会出现相同的错误。 - Venkatesh Dharavath
谢谢,我的情况是“确认了不应该确认的消息”。 - undefined

13

(以下为解决方案)

引用Jan Grzegorowski在他的博客中的话:

If you are struggling with the 406 error message which is included in title of this post you may be interested in reading the whole story.

Problem

I was using amqplib for conneting NodeJS based messages processor with RabbitMQ broker. Everything seems to be working fine, but from time to time 406 (PRECONDINTION-FAILED) message shows up in the log:

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

Solution <--

Keeping things simple:

  • You have to ACK messages in same order as they arrive to your system
  • You can't ACK messages on a different channel than that they arrive on If you break any of these rules you will face 406 (PRECONDITION-FAILED) error message.

原始回答


9

2

如果您重复确认相同的消息,则可能会出现此错误。


2

关于对消息进行两次确认的变体:
有一种“模糊”的情况,即当您使用multiple参数将消息确认多次时,所有在您尝试确认的消息之前的消息也将被确认。
因此,如果您尝试确认已通过设置多个值自动确认的消息之一,则会尝试多次“确认”它,从而导致错误。这可能有些令人困惑,但希望您在阅读几遍后能理解。


尝试编辑以使您的答案更清晰,但遇到了“编辑队列已满”的问题。请尝试将其分成段落,并按以下注释中的行进行操作。 - Yılmaz Durmaz
关于上面提到的两次确认的变体: - Yılmaz Durmaz
有一种“晦涩难懂”的情况,即当您使用多个参数对消息进行确认时,也就是将所有之前的消息都确认了,这意味着您正在尝试确认的消息以及之前的所有消息都会被确认。 - Yılmaz Durmaz
如果您尝试通过将multiple设置为true来确认已经被“自动确认”的消息之一,那么您将尝试多次确认它,从而导致错误。 - Yılmaz Durmaz
好的,我稍微改进了一下。谢谢。 - Melardev

0

确保您拥有正确的application.properties文件:

如果您使用RabbitTemplate而没有任何通道配置,请使用"simple":

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

在这种情况下,如果您使用“直接”而不是“简单”,您将收到相同的错误消息。另一个看起来像这样:
spring.rabbitmq.listener.direct.acknowledge-mode=manual

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