DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

Celery 长 countdown 后报 consumer ack timed out

长countdown等待可能超过RabbitMQ确认期限。核对版本与队列类型,区别毫秒和秒,并检查channel关闭后的重新入队。

Celery worker 已接收远期 ETA 任务,尚未开始执行,随后报 PRECONDITION_FAILED - consumer ack timed out on channel 或 delivery acknowledgement ... timed out。如果使用 RabbitMQ,先检查消息从投递到确认的间隔是否超过 consumer_timeout。心跳正常,也不能延长消息的确认期限。

长 ETA 是其中一种原因,执行很慢且采用晚确认的任务也可能触发。需要对照出错队列、RabbitMQ 版本、任务时间线和实际确认配置,不要把所有 channel 关闭都解释为 countdown 过长。

先核对版本与队列类型

RabbitMQ 3.8.15 引入的默认确认超时为十五分钟,3.8.17 起默认为三十分钟。旧部署升级后出现问题,可能是原来未触发的确认期限开始生效,并不意味着只升级 Celery 就能解决。

版本边界还在变化:RabbitMQ 4.3 起,delivery acknowledgement timeout 只支持 quorum queues。检查当前服务端版本、实际队列类型及生效配置;不能把旧版本 classic queue 的错误原样套到 4.3 的所有队列上。

Celery 5.6.3 的 ETA 规则是先由 worker 接收并留在内存,直到开始执行才确认预约任务。因此,task_acks_late=False 也不能保证远期 ETA 在接收瞬间完成确认。启用晚确认时,还要将实际运行时间纳入预算。

长预约优先调整派发方式

把长期计划持久保存,由调度器接近到期时向队列派发,可以减少 worker 持有未确认消息的时长和内存占用。调度器必须保留业务标识、派发与重试记录,处理故障恢复;不要通过删掉 ETA 参数把本应未来执行的任务提前执行。

expires 控制任务过期,不会延长 RabbitMQ 的确认期限。提高心跳、减少日志或关闭 Celery 的晚确认,也不能代替对预约等待阶段的处理。

确需调整时,注意毫秒和配置范围

RabbitMQ 的 consumer_timeout 使用毫秒;Celery countdown 使用秒。先限定可接受的最大等待时间,再加上需要晚确认的执行时间和合理余量。下面只是经过评估后的一小时配置示例,写在对应节点的 rabbitmq.conf 中:

consumer_timeout = 3600000

按该版本部署方式让配置生效,并核对连接到的实际节点。节点级设置会影响其他消费者,不要因为一类预约任务就盲目扩大整个集群的预算。

RabbitMQ 3.12 起支持队列级 consumer-timeout 策略和声明时的 x-consumer-timeout 参数,可在版本及队列类型支持的范围内缩小调整范围。现有策略可能还有其他配置,先审查再变更;已有队列声明参数不一定能直接重新声明修改,需按实际队列属性安排。

超时检查大约每分钟进行一次。低于一分钟的值不受支持,低于五分钟不推荐;用 consumer_timeout=5 配合十秒 countdown,没有立即报错,不能说明确认超时不起作用。这里的 5 还是五毫秒,并非五秒。

不要把期限改成一年,也不要默认禁用这项保护。长时间未确认的消息会妨碍数据回收,需要在任务调度与服务恢复之间作有界取舍。

channel 恢复后检查全部未确认任务

触发确认超时后,RabbitMQ 关闭 channel,其上未确认的投递可能重新入队;受影响的未必只有日志里那一个任务。记录 channel、队列和业务标识,查看恢复后的重投递与业务结果,避免副作用重复发生。

在隔离队列验证正常预约、最长允许等待、需要晚确认的运行过程,以及 worker 退出后的恢复。验收不只看 worker 又连上了 broker,还要确认任务按要求开始、完成与确认,并且重复投递不会重复扣款、发信或写入业务结果。

Redis broker 的同类预约重复有另一套秒数配置,见ETA 超过 visibility_timeout 后的重复投递。两种 broker 的参数不能互相替用。