task_acks_late=true 表示celery在任务执行完成后再向消息代理确认,而非取到任务即确认,从而避免worker崩溃导致任务丢失;但需配合队列持久化、消息持久化及broker重入队支持才能真正保障可靠性。

直接说结论:Django 本身不处理消息队列的可靠性,acks_late 是 Celery 的配置项,不是 Django 的;真正起作用的是 Celery + RabbitMQ/Kafka 的组合配置,且必须同时满足队列持久化、消息持久化、手动 ACK 三者,缺一不可。
celery 的 acks_late=True 到底在做什么
它控制的是「消费者端何时发送 ACK」——设为 True 后,Celery 会在任务函数执行**完成之后**才向 Broker 发送确认,而不是一拿到消息就确认。这能防止消费者进程崩溃导致消息被静默丢弃。
但注意:acks_late=True 本身不保证消息不丢失,它只解决「消费中途挂掉」的问题。如果 Broker 重启、网络断开、或消息根本没写进磁盘,照样丢。
-
acks_late=False(默认):消息一被取走就发 ACK,哪怕任务函数还没跑完,宕机即丢 -
acks_late=True:必须等任务函数 return 或 raise 才发 ACK;若 crash,RabbitMQ 会把消息重新入队(前提是没被basic_nack(requeue=False)拒绝) - 它依赖底层 Broker 支持重入队逻辑,RabbitMQ 默认支持,Kafka 需配合 offset 手动提交
RabbitMQ 队列和消息都得设 durable=True
只声明持久化队列,不设消息持久化,Broker 重启后队列还在,但里面的消息全空了——因为消息默认只存在内存里。
在 Celery 中,这不是靠 Django settings 控制的,而是通过 task_queue 声明或 broker_url 参数间接影响。实际生效点在 pika 层:
- 队列声明必须带
durable=True:Celery 默认会这样建(只要CELERY_TASK_DEFAULT_QUEUE对应的 queue 在task_queues中显式配置了durable=True) - 消息必须带
delivery_mode=2:Celery 从CELERY_TASK_SERIALIZER='json'和CELERY_RESULT_SERIALIZER='json'开始,默认就用持久化模式发消息,但前提是没被中间件覆盖 - 验证方式:用
rabbitmqctl list_queues name durable auto_delete看队列是否标记true;用Wireshark或日志确认 AMQP header 里有delivery_mode=2
Django/Celery 配置里容易漏掉的关键项
Celery 的可靠性不是开个开关就完事,几个配置项互相制约,漏一个就前功尽弃:
-
CELERY_ACKS_LATE = True:必须设,否则acks_late不生效 -
CELERY_TASK_ACKS_LATE = True(旧版 alias,建议统一用前者) -
CELERY_WORKER_PREFETCH_MULTIPLIER = 1:避免 Worker 预取多条消息后挂掉,导致多条卡在 unack 状态无法重试 -
CELERY_TASK_REJECT_ON_WORKER_LOST = True:Worker 强制 kill 时主动 nack,而非等待超时 - 禁用
CELERY_TASK_EAGER = True:本地调试时容易误开,它绕过 Broker 直接同步执行,完全不走持久化链路
死信队列(DLX)是兜底,不是摆设
反复失败的消息不能一直重试,得进死信队列做人工干预或自动归档。RabbitMQ 要求你提前声明 DLX 和 DLQ,并绑定到原队列:
在 Celery 中,不能只靠 autoretry_for,得让底层 channel 支持 DLX。常用做法是用 task_routes 绑定自定义队列,并传入 queue_arguments:
CELERY_TASK_ROUTES = {
'myapp.tasks.process_image': {
'queue': 'image_queue',
'routing_key': 'image',
},
}
CELERY_TASK_QUEUES = {
'image_queue': {
'exchange': 'image_exchange',
'exchange_type': 'direct',
'routing_key': 'image',
'queue_arguments': {
'x-dead-letter-exchange': 'dlx',
'x-dead-letter-routing-key': 'dlq',
'x-message-ttl': 600000, # 10分钟
}
}
}
这个配置必须和 RabbitMQ 的 DLX 交换机、DLQ 队列实际存在匹配,否则 x-dead-letter-exchange 会静默失效——这是最常被忽略的环节。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











