任务长时间显示reserved或started状态,表明worker已取走任务但未完成,可能卡在I/O、死锁或未捕获异常中;需检查inspect reserved/active、启用task_track_started和acks_late、验证进程是否僵死、并确保Django连接在fork后正确关闭。

任务在 celery 中长时间显示 reserved 或 started 状态
这通常意味着 worker 已取走任务但没完成,或卡在某个 I/O、死锁、超时未处理的异常里。默认情况下 celery 不会主动中断正在运行的任务,哪怕它已卡住数小时。
- 检查
celery -A your_project inspect reserved和inspect active,确认任务是否真在运行,还是只是状态没更新 - 启用
task_track_started=True并配合acks_late=True,避免 worker 崩溃后任务丢失,同时让状态更真实反映执行进度 - 在任务函数开头加
print(f"[{os.getpid()}] START {task_id}"),配合ps aux | grep celery查看对应进程是否僵死 - 注意 Django 数据库连接在 fork 后未关闭:worker 启动时若已建立连接,子进程复用该连接可能因连接超时或事务未提交导致阻塞——务必在
task_prerun信号中调用django.db.close_old_connections()
celery beat 调度正常但任务从不进入 ready 队列
调度器生成了任务,但 broker(如 Redis/RabbitMQ)没收到,或收到后被丢弃。这不是 worker 问题,而是调度链路断在中间。
- 确认
beat进程运行且无KeyError或No route found日志;常见错误是CELERYBEAT_SCHEDULE中任务名拼错,比如写成"myapp.tasks.send_mail"但实际函数是send_email - 用
redis-cli -h your-redis lrange "celery" 0 10(Redis backend)或rabbitmqctl list_queues直接查队列长度,验证任务是否真入队 - 检查
task_default_queue和task_routes配置是否把任务导流到一个不存在或权限受限的队列,例如 RabbitMQ 中未声明该 queue 或未绑定 exchange - 若使用
django-celery-beat,注意其数据库表periodictasks的last_run_at字段更新失败(如 DB 连接中断)会导致 beat 停止调度,需手动触发python manage.py celerybeat观察日志
Django ORM 操作在 Celery 任务中持续慢或超时
Celery 任务默认共享 Django 的数据库连接池配置,但长时任务或高并发下容易耗尽连接,尤其当使用 CONN_MAX_AGE=0 时每次查询都新建连接,加剧 Redis 或 DB 压力。
- 在任务中避免
Model.objects.all().list()类全量加载;改用iterator(chunk_size=2000)或分页游标 - 显式控制事务:用
@transaction.atomic(using='default')包裹写操作,防止长事务阻塞其他 worker 的读写 - 检查
OPTIONS['MAX_CONNS'](如 psycopg2)和CONN_MAX_AGE是否与 worker 并发数匹配;例如 4 个 worker × 每个最多 20 连接 = 至少需 DB 支持 80 连接 - 禁用 Django 的自动 commit 行为(
ATOMIC_REQUESTS=True在任务中反而有害),改为手动控制transaction.on_commit()处理异步依赖
Redis 内存满或连接数打满导致任务堆积
Redis 作为 broker + result backend 时,既是消息管道又是状态存储,一出问题整个队列就雪崩。现象常是 ConnectionError: Error 111 connecting to localhost:6379 或任务延迟飙升但无报错。
立即学习“Python免费学习笔记(深入)”;
- 运行
redis-cli info memory | grep -E "(used_memory|maxmemory|mem_fragmentation_ratio)",确认是否触发maxmemory-policy导致 key 被驱逐(如误删 broker 的celerylist) - 检查
redis-cli client list | wc -l,对比maxclients配置;Celery 默认每个 worker 建多个连接(broker + result backend + monitor),10 个 worker 可能占用 30+ 连接 - 避免把
result_backend和broker_url指向同一 Redis DB:不同 DB 间不隔离连接,易互相干扰;推荐 broker 用 DB 0,result 用 DB 1 - 临时降级:将
result_backend改为django-db或rpc://,减轻 Redis 压力,再逐步排查慢查询或大结果序列化(如return queryset)


















