Celery任务不执行的根本原因是broker连接失败或序列化配置不一致,需检查CELERY_BROKER_URL地址、显式设置JSON序列化、worker日志级别,并确保task被正确导入和beat与worker配置一致。

为什么 Celery 启动后任务根本不执行,连 apply_async() 都没反应
常见现象是调用 task.apply_async() 返回一个 AsyncResult 对象,但日志里看不到任务被 worker 拿走,Redis 里也查不到对应消息。根本原因往往不是代码写错,而是 broker 连接失败或序列化配置不一致。
- 确认
CELERY_BROKER_URL指向的是 Redis 实例地址,不是redis://localhost:6379/0这种默认值 —— 很多开发环境 Redis 是用 Docker 跑的,host 应该是redis(容器名)而非localhost - Django settings 中必须显式设置
CELERY_TASK_SERIALIZER = 'json'和CELERY_RESULT_SERIALIZER = 'json';如果用了pickle,worker 和 Django 进程 Python 版本或包路径稍有差异就会静默失败 - 启动 worker 时一定要加
--loglevel=info,否则默认warning级别会吞掉连接拒绝、认证失败等关键提示
celery -A myproject worker 报 KeyError: 'default' 或找不到 task
这是 Django 项目结构和 Celery 自动发现机制不匹配的典型表现。Celery 不会自动扫描 apps 下所有 tasks.py,它只认 INSTALLED_APPS 里注册过的 app 的根目录下的 tasks.py,且要求该文件被 import 过。
- 确保每个需要注册 task 的 app 目录下有
tasks.py,且内容至少包含一个带@shared_task或@app.task装饰器的函数 - 在 app 的
__init__.py或apps.py中主动 import 一次tasks,比如from . import tasks—— 否则 Celery 初始化时根本不会加载它 - 不要把 task 写在
views.py或models.py里,Celery worker 启动时不加载这些模块
定时任务 beat 一直报 NotRegistered,但手动触发却正常
celery beat 是独立进程,它不运行 Django 上下文,也不导入你的 tasks.py。它只从 CELERY_BEAT_SCHEDULE 字典里读取 task 名字符串,然后靠 registry 去匹配 —— 如果 registry 里没有,就直接炸。
-
CELERY_BEAT_SCHEDULE中每个 task 的值必须是完整路径字符串,例如'myapp.tasks.send_daily_report',不能是函数对象或未加引号的引用 - 确保
celery beat和celery worker使用同一份配置(尤其是imports和include),推荐统一从 Django settings 加载:app.config_from_object('django.conf:settings', namespace='CELERY') - Redis 作为 broker 时,
beat会往 Redis 写一个celery:beat:lockkey,如果上一次没正常退出,这个锁可能残留,导致新 beat 不敢发任务 —— 手动redis-cli DEL celery:beat:lock即可
Django shell 里调用 task.delay() 成功,但生产环境 Nginx + Gunicorn 下完全不触发
这不是 Celery 的问题,而是部署时漏掉了关键进程管理环节。Gunicorn 只管 HTTP 请求,它不会顺手帮你拉起 celery worker 或 celery beat。
立即学习“Python免费学习笔记(深入)”;
- 生产环境必须用
systemd、supervisord或 Docker Compose 分别守护gunicorn、celery worker、celery beat三个进程,缺一不可 - 检查 Gunicorn 启动用户是否有权限访问 Redis(比如 Redis 绑定了 Unix socket 且权限为
redis:redis,而 gunicorn 以www-data运行) - 异步任务中若调用了 Django ORM,务必在 task 函数开头加
django.setup()(仅当 worker 未通过 Django 集成启动时才需要,但很多一键部署脚本会跳过这步)
@shared_task,而是 broker 连不上、task 导入链断了、beat 和 worker 配置不一致、或者压根忘了在服务器上跑 worker 进程。这些地方一旦出问题,表现都是“没反应”,而不是报错。










