RabbitMQ PRECONDITION_FAILED - 未知的交付标签
RabbitMQ PRECONDITION_FAILED - unknown delivery tag
我们有一个 PHP 应用程序,它通过 WebSocket 连接将消息从 RabbitMQ 转发到连接的设备(PHP AMQP pecl 扩展 v1.7.1 和 RabbitMQ 3.6.6)。
消息从队列数组中消费(每个 websocket 连接 1 个),并在我们通过 websocket 收到消息已收到的确认时由消费者确认(因此我们可以重新排队未传递的消息可接受的时间范围)。这是以非阻塞方式完成的。
99% 的情况下,这都能完美运行,但偶尔我们会收到错误 "RabbitMQ PRECONDITION_FAILED - unknown delivery tag "。这将关闭通道。据我了解,此异常是以下情况之一的结果:
- 邮件已经被确认或拒绝。
- 尝试通过未传递消息的通道进行确认。
- 在消息超时 (ttl) 到期后尝试确认。
我们对上述每种情况都实施了保护措施,但问题仍然存在。
我知道有很多实施细节可能会影响这一点,但在概念层面上,是否还有我们没有考虑但应该处理的其他失败案例?还是有更好的方法来实现上述功能?
"PRECONDITION_FAILED - unknown delivery tag"通常是因为双重确认、错误频道确认或确认不应确认的消息而发生。
因此,在相同的情况下,您需要执行 basic.ack
两次或 basic.ack
使用另一个通道
(下面的解决方案)
引自 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.
如果您两次确认同一条消息,就会出现此错误。
如果您将 Consumer 的 no-ack
选项设置为 true
则可能会发生这种情况,这意味着您不能手动调用 ack
函数:
https://www.rabbitmq.com/amqp-0-9-1-reference.html#basic.consume.no-ack
解决方法:设置no-ack
标志为false
。
确保你有正确的 application.properties:
如果您在没有任何通道配置的情况下使用 RabbitTemplate,请使用“简单”:
spring.rabbitmq.listener.simple.acknowledge-mode=manual
在这种情况下,如果您使用“直接”而不是“简单”,您将收到相同的错误消息。另一个看起来像这样:
spring.rabbitmq.listener.direct.acknowledge-mode=manual
他们上面所说的关于确认它两次的变体:
有一种“晦涩”的情况,您不止一次确认一条消息,即当您确认 multiple
参数设置为 true 的消息时,这意味着您尝试确认的所有先前消息都将也被ack了。
因此,如果您尝试通过将 multiple 设置为 true 来确认其中一条被“自动确认”的消息,那么您将尝试多次“确认”它,因此错误会令人困惑,但希望您在阅读几次后能理解它。
如果您使用 docker 遇到此队列错误,重新启动相应的容器将修复错误。
我们有一个 PHP 应用程序,它通过 WebSocket 连接将消息从 RabbitMQ 转发到连接的设备(PHP AMQP pecl 扩展 v1.7.1 和 RabbitMQ 3.6.6)。
消息从队列数组中消费(每个 websocket 连接 1 个),并在我们通过 websocket 收到消息已收到的确认时由消费者确认(因此我们可以重新排队未传递的消息可接受的时间范围)。这是以非阻塞方式完成的。
99% 的情况下,这都能完美运行,但偶尔我们会收到错误 "RabbitMQ PRECONDITION_FAILED - unknown delivery tag "。这将关闭通道。据我了解,此异常是以下情况之一的结果:
- 邮件已经被确认或拒绝。
- 尝试通过未传递消息的通道进行确认。
- 在消息超时 (ttl) 到期后尝试确认。
我们对上述每种情况都实施了保护措施,但问题仍然存在。
我知道有很多实施细节可能会影响这一点,但在概念层面上,是否还有我们没有考虑但应该处理的其他失败案例?还是有更好的方法来实现上述功能?
"PRECONDITION_FAILED - unknown delivery tag"通常是因为双重确认、错误频道确认或确认不应确认的消息而发生。
因此,在相同的情况下,您需要执行 basic.ack
两次或 basic.ack
使用另一个通道
(下面的解决方案)
引自 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.
如果您两次确认同一条消息,就会出现此错误。
如果您将 Consumer 的 no-ack
选项设置为 true
则可能会发生这种情况,这意味着您不能手动调用 ack
函数:
https://www.rabbitmq.com/amqp-0-9-1-reference.html#basic.consume.no-ack
解决方法:设置no-ack
标志为false
。
确保你有正确的 application.properties:
如果您在没有任何通道配置的情况下使用 RabbitTemplate,请使用“简单”:
spring.rabbitmq.listener.simple.acknowledge-mode=manual
在这种情况下,如果您使用“直接”而不是“简单”,您将收到相同的错误消息。另一个看起来像这样:
spring.rabbitmq.listener.direct.acknowledge-mode=manual
他们上面所说的关于确认它两次的变体:
有一种“晦涩”的情况,您不止一次确认一条消息,即当您确认 multiple
参数设置为 true 的消息时,这意味着您尝试确认的所有先前消息都将也被ack了。
因此,如果您尝试通过将 multiple 设置为 true 来确认其中一条被“自动确认”的消息,那么您将尝试多次“确认”它,因此错误会令人困惑,但希望您在阅读几次后能理解它。
如果您使用 docker 遇到此队列错误,重新启动相应的容器将修复错误。