Celery 4.4.7 跑 OCR 任务,worker 放在 8GB 容器里,OOM killer 杀掉一个 worker 后,该任务在 Flower 里一直显示 STARTED,十分钟也没重投,队列里也看不到这条消息,手动补发才把任务捞回来。

原因不止一个,得分开看。task_reject_on_worker_lost 默认是 False;没开 acks_late 消息在派发时就已确认;broker 的 visibility_timeout 设成了 12 小时;result backend 里的中间状态没人清理。

先查 worker 当前生效的配置

celery -A app inspect conf | findstr reject_on_worker_lost

随后打开两个开关并缩短可见性超时

python -c "print({'task_reject_on_worker_lost':True,'task_acks_late':True,'broker_transport_options':{'visibility_timeout':1800}})"

手动 kill 一个 worker 复现重投

docker kill $(docker ps -qf name=celery-worker-2)

末了观察 active 与 reserved 列表

celery -A app inspect active && celery -A app inspect reserved

这台环境是别人交接的,不少默认值被动过,只能一项项核。

同事提醒我看一下最近一次发布,时间点确实对得上。

命令输出我都留了记录,免得改完记不清原来的值。

改之前先确认了最近有没有人动过配置,避免白查一遍。

恢复的判定其实很直接。kill 之后 30 秒内任务重新出现在 active,最终状态为 SUCCESS,数据库里只落一条结果。

acks_late 的语义是至少执行一次,业务侧必须用幂等键兜住重复执行,否则重投会带来重复数据。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。

作者 9823189