celery任务不执行的首要原因是worker未启动或broker连接失败;需运行celery -a project worker --loglevel=info确认ready状态,检查celery_broker_url配置及redis服务是否运行。

Celery 任务在 Django 里不执行,90% 的情况不是代码写错了,而是 celery worker 根本没跑起来,或者连不上 Redis。
为什么 delay() 调用了但任务没反应
调用 task.delay() 只是把任务序列化后塞进 Redis,它不会自动触发执行。Django 进程和 Celery worker 是两个完全独立的进程,Django 启动时绝不会顺手拉起 worker。
- 运行
celery -A myproject worker --loglevel=info,观察终端是否输出Ready和已注册的 task 名;没出现就说明 worker 没启动或配置没加载 - 如果报
ConnectionRefusedError,检查CELERY_BROKER_URL地址、端口、数据库编号(比如redis://127.0.0.1:6379/0)是否和 Redis 实际运行一致 - 如果卡在
App is not configured,大概率是celery.py里没设os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings'),或__init__.py没导出celery_app
tasks.py 里访问 Django model 容易崩
worker 进程启动时,Django ORM 尚未 ready,不能在 tasks.py 文件顶层直接 import 并使用 User.objects.all() 这类操作,否则会抛 AppRegistryNotReady。
- 所有 model 查询、保存必须包在 task 函数体内,等函数真正执行时再查库
- 不要传 model 实例进 task(序列化失败),只传主键(如
user_id),进函数后再User.objects.get(id=user_id) - 优先用
@shared_task而非@app.task,避免因 app 加载顺序导致的循环引用
Broker 和 Result Backend 都用 Redis 怎么配
用同一个 Redis 实例但不同 db 是最轻量、最稳妥的选择,避免 SQLite 在多 worker 下锁表或损坏。
-
CELERY_BROKER_URL = 'redis://127.0.0.1:6379/0'—— 任务队列专用,别混用其他业务数据 -
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/1'—— 结果存储专用,和 broker 分开 db 更安全 - 必须加
INSTALLED_APPS += ['django_celery_results'](哪怕不用 database backend),否则某些版本会静默失败 -
CELERY_TASK_SERIALIZER = 'json'和CELERY_RESULT_SERIALIZER = 'json'必须显式设,避免 pickle 带来的安全与兼容问题
异步任务失败后怎么定位和重试
Celery 默认失败不抛异常,日志也不打全,光看 delay() 返回值根本不知道它到底卡在哪。
- 加
--loglevel=info启动 worker,失败时会打印 traceback;加--pool=solo可让错误直接抛到终端,方便调试 - 用
apply_async(..., countdown=60)或eta=datetime.now() + timedelta(seconds=30)控制延迟执行,比裸写time.sleep可靠得多 - 重试要靠
autoretry_for=(Exception,)和retry_kwargs={'max_retries': 3}显式声明,否则失败就丢弃 - 任务函数里别写裸
print(),用self.logger.info(),日志才能被 Celery 统一捕获
最常被忽略的是:worker 进程一旦启动,就不会重新加载你改过的 tasks.py,改完代码必须手动重启 celery worker,否则永远在跑旧逻辑。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











