Celery Periodic Task在Heroku上按crontab配置不执行问题
解决Heroku上Celery定时任务部分不执行的问题
我之前在Heroku部署Celery定时任务时也碰到过几乎一模一样的情况,结合你的日志和配置,咱们一步步来排查解决:
1. 优先排查时区问题(这是Heroku上Celery定时任务最常见的坑)
从日志能看到服务器用的是UTC时区,而你的本地环境大概率是本地时区。你设置的invoice_simulation任务是每月3-11号的11:32执行,但这个时间如果是基于你本地时区定义的,到了UTC时区的Heroku服务器上,实际执行时间会偏移时区差,甚至可能不在你预期的日期范围内。
解决步骤:
- 在Django的
settings.py里明确配置时区:TIME_ZONE = 'Asia/Shanghai' # 替换成你的实际时区,比如'Europe/London' USE_TZ = True - 让Celery同步使用Django的时区,在Celery配置文件(比如
celery.py)里添加:from django.conf import settings app.conf.timezone = settings.TIME_ZONE
2. 拆分Celery Worker和Beat进程
你现在用celery -A mdn_core_engine worker -B在同一个dyno里同时跑Worker和Beat,但Heroku的dyno环境对进程管理有一定限制,可能导致Beat的调度逻辑不稳定,出现任务漏跑的情况。
解决步骤:
- 单独创建两个dyno分别运行:
- 一个专门跑Beat调度:
celery -A mdn_core_engine beat --loglevel=info - 另一个跑任务执行Worker:
celery -A mdn_core_engine worker --loglevel=info
- 一个专门跑Beat调度:
- 推荐使用持久化调度器,避免dyno重启后丢失调度状态:
- 安装依赖包:
pip install django-celery-beat - 将包添加到Django的
INSTALLED_APPS:'django_celery_beat', - 执行数据库迁移:
python manage.py migrate - 在Celery配置里指定调度器:
app.conf.beat_scheduler = 'django_celery_beat.schedulers:DatabaseScheduler'
- 安装依赖包:
3. 验证任务本身的可执行性
虽然本地正常,但可以临时修改invoice_simulation的调度规则,改成每分钟执行一次,测试在Heroku上能不能触发:
from celery.utils.log import get_task_logger logger = get_task_logger(__name__) @periodic_task(run_every=(crontab(minute='*')), name="invoice_simulation", ignore_result=False) def invoice_simulation(): logger.info('---- invoice_simulation task started-----') # 执行相关操作
然后用heroku logs --tail --app 你的应用名称实时查看日志,确认任务是否有输出。
4. 核对crontab表达式的实际执行时间
再确认下crontab(day_of_month='3-11', hour=11, minute=32)在UTC时区下的实际时间。比如如果你的本地时区是UTC+8,服务器上的11:32 UTC对应你本地的19:32,如果你误以为任务会在本地11:32执行,那它其实会在你本地晚上运行,可能没注意到日志输出。
内容的提问来源于stack exchange,提问作者Shubham Srivastava
相关产品推荐
相关产品推荐

