Celery在Django中定时任务失败的核心原因是Broker连接失败、Worker未正确加载Django配置、时区设置不一致;需确保Redis/RabbitMQ可达、显式配置app.config_from_object、统一CELERY_TIMEZONE与CELERY_ENABLE_UTC。

直接说结论:Celery 在 Django 里跑定时任务,核心不是“怎么配”,而是“Broker 通不通、Worker 启没启、时区对不对”。配错一半的坑都出在这三处。
为什么 celery -A myproject worker 启动后任务不执行?
最常见的原因是 Broker 连接失败,但日志里往往只报 Connection refused 或静默退出。Django 项目里 Celery 默认用 django.conf.settings 初始化,但 worker 进程不加载 Django settings —— 所以必须显式指定配置模块。
- 确保
myproject/celery.py中的app = Celery('myproject')后有app.config_from_object('django.conf:settings', namespace='CELERY') -
CELERY_BROKER_URL必须在settings.py里明确定义,不能只靠环境变量(worker 不读取.env) - 用
redis://localhost:6379/0时,先redis-cli ping确认 Redis 活着;用 RabbitMQ 则检查amqp://guest:guest@localhost//是否可连 - 启动命令必须带
-l info:celery -A myproject worker -l info,否则连连接失败都不打日志
@shared_task 和 @task 该选哪个?
用 @shared_task。它不依赖具体 app 实例,适合放在 tasks.py 里被多个 app 引用;而 @task 需绑定到某个 app 实例,在 Django 项目中容易因导入顺序导致循环引用。
-
@shared_task自动从当前 Celery app(即myproject.celery.app)注册,无需手动app.task() - 如果任务需访问 Django ORM,务必在函数开头加
django.setup()(仅当 worker 未自动加载 Django 时)—— 但更稳妥的做法是:确保__init__.py或celery.py已调用django.setup() - 避免在 task 函数里 import model 顶层,改用
from django.apps import apps+apps.get_model('app_name', 'ModelName')动态获取
CELERY_BEAT_SCHEDULE 定时任务总差 8 小时?
这是 Django 和 Celery 时区配置不一致导致的典型问题。Django 默认用 TIME_ZONE = 'UTC',但 Celery beat 默认用系统本地时区解析 crontab 表达式。
立即学习“Python免费学习笔记(深入)”;
- 必须统一设为 UTC:
CELERY_TIMEZONE = 'UTC',且CELERY_ENABLE_UTC = True -
CELERY_BEAT_SCHEDULE中的schedule值(如crontab(minute=0, hour=2))按 UTC 解释,不是服务器本地时间 - 若业务必须按东八区跑,可设
CELERY_TIMEZONE = 'Asia/Shanghai',但要确保所有机器时区一致,且crontab参数按上海时间写(比如凌晨 2 点 →hour=2),同时CELERY_ENABLE_UTC = False - 修改后重启
celery -A myproject beat,别忘了也重启worker,beat 只发任务,worker 才执行
真正卡住人的地方,从来不是语法,而是 broker 连不上、worker 没读到 settings、时区算错时间点——这些地方日志不报错,但任务就是不动。多看 worker 启动时的第一行输出,确认它加载的是你改过的 settings 文件,而不是缓存或旧路径。


















