PRECONDITION_FAILED:带有 Gevent 和并发的 Celery 和 RabbitMQ 上的传递确认超时

我刚刚从 ForkPool 切换到 gevent,并发 (5) 作为在 Kubernetes pod 中运行的 Celery 工作人员的池方法。切换后,我在工作人员中遇到了不可恢复的错误:

amqp.exceptions.PreconditionFailed: (0, 0): (406) PRECONDITION_FAILED - delivery acknowledgement on channel 1 timed out. Timeout value used: 1800000 ms. This timeout value can be configured, see consumers doc guide to learn more

代理日志给出了基本相同的消息:

2021-11-01 22:26:17.251 [warning] <0.18574.1> Consumer None4 on channel 1 has timed out waiting for delivery acknowledgement. Timeout used: 1800000 ms. This timeout value can be configured, see consumers doc guide to learn more

我已经设置了 CELERY_ACK_LATE ,但不熟悉为确认期设置超时的必要性。这在使用流程之前从未发生过。任务可能相当长(有时 60-120 秒),但我找不到特定的设置来允许它。

我在其他论坛的另一篇文章中读到了一个用户,他将代理配置的超时设置为一个巨大的数字(比如 24 小时),并且也遇到了同样的问题,所以这让我觉得可能还有其他与问题。

关于如何使工人更有弹性的任何想法或建议?

stack overflow PRECONDITION_FAILED: Delivery Acknowledge Timeout on Celery & RabbitMQ with Gevent and concurrency
原文答案
author avatar

接受的答案

为了将来参考,似乎新的 RabbitMQ 版本(+3.8)为 consumer_timeout 引入了一个严格的默认值(我认为是 15 分钟)。

我找到的解决方案(不久前也已添加到 Celery 文档 here 中)是在 RabbitMQ 中为 consumer_timeout 添加一个大数字。

this question 中,有人提到将 consumer_timeout 设置为 false,以一种不需要使用大量数字的方式,但显然有一些关于配置格式的细节才能起作用。

我在 k8s 中运行 RabbitMQ 并做了类似的事情:

rabbitmq.conf: |
  consumer_timeout = 31622400000

答案:

作者头像

接受的答案是正确的答案。但是,如果您有一个现有的 RabbitMQ 服务器正在运行并且不想重新启动它,您可以通过在 RabbitMQ 服务器上运行以下命令来动态设置配置值:

rabbitmqctl eval 'application:set_env(rabbit, consumer_timeout, 36000000).'

这会将新超时设置为 10 小时(36000000 毫秒)。要使其生效,您需要重新启动您的工作人员。现有的工作连接将继续使用旧的超时。

您还可以检查当前配置的超时值:

rabbitmqctl eval 'application:get_env(rabbit, consumer_timeout).'

如果你通过 Docker 镜像运行 RabbitMQ,这里是设置值的方法:只需将 -e RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="-rabbit consumer_timeout 36000000" 添加到 docker run 或将环境 RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS 设置为 "-rabbit consumer_timeout 36000000"

希望这可以帮助!