新增任务后Celery Beat不再执行原有定时任务(Django环境)
我运行着一个基于Django 4.2.2、Python 3.10.12、Celery 5.4.0、Celery Beat 2.6.0、Django Celery Results 2.5.1、Redis与Postgres的应用。
Celery配置
CELERY_BROKER_URL = "redis://localhost:6379/3"
from __future__ import absolute_import, unicode_literals from celery import Celery from django.conf import settings import os import django # Set the DJANGO_SETTINGS_MODULE before calling django.setup() os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'auctopus.settings') django.setup() # Initialize Celery app = Celery('proj') app.conf.enable_utc = False app.conf.broker_connection_retry_on_startup = True app.conf.task_serializer = 'json' app.conf.accept_content = ['application/json'] app.conf.result_serializer = 'json' app.conf.timezone = 'Asia/Kolkata' app.conf.cache_backend = 'default' app.conf.database_engine_options = {'echo': True} app.conf.result_backend = 'django-db' app.conf.result_expires = 3600 app.conf.task_time_limit = 1000 app.conf.task_default_queue ='default' app.conf.worker_concurrency = 6 app.config_from_object(settings, namespace='CELERY') # Autodiscover tasks from installed apps app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) app.conf.beat_scheduler = 'django_celery_beat.schedulers:DatabaseScheduler'
问题现象
Django应用启动后,会自动创建多个基于IntervalSchedule的调度任务,如internet_status_check、system_resource_check等。初始运行正常,但一旦新增任何IntervalSchedule或CrontabSchedule类型的调度任务,原有运行的调度任务就会停止执行,Celery Beat终端会显示“DatabaseScheduler: Schedule changed”的提示。此后即使Django管理面板中可见待执行任务,Beat也不会发送任务执行请求。
已尝试的排查措施:
- 更换Broker为RabbitMQ,问题依旧
- 修改
result_backend为Redis/django-db,问题依旧 - 重启Celery Beat无法恢复任务执行
临时解决方法(非长久之计):
通过Django Shell将所有任务的last_run_at设为None并调用changed()方法:
from django_celery_beat.models import PeriodicTask, PeriodicTasks PeriodicTask.objects.all().update(last_run_at=None) for task in PeriodicTask.objects.all(): PeriodicTasks.changed(task)
请问该如何彻底解决此问题?是我的配置遗漏,还是Celery Beat调度器本身存在Bug?
1. 确保时区完全一致
检查Django settings.py中的时区配置,必须与Celery配置的timezone完全匹配:
# settings.py TIME_ZONE = 'Asia/Kolkata' USE_TZ = True
时区不匹配会导致调度器计算任务下次执行时间时出现偏差,新增任务触发调度更新后,原有任务的时间逻辑可能彻底失效。
2. 关闭数据库SQL日志输出
当前配置中app.conf.database_engine_options = {'echo': True}会开启SQL语句打印,大量日志会干扰Beat的数据库查询逻辑(尤其是调度更新时的锁机制和时间戳计算)。建议注释或删除该配置:
# app.conf.database_engine_options = {'echo': True}
3. 缩短Beat调度检查间隔
启动Celery Beat时添加--schedule-freq参数,强制缩短数据库任务检查周期,确保新增任务后调度器能及时重新加载所有任务:
celery -A proj beat -l info --schedule-freq=10
该命令设置Beat每10秒检查一次数据库任务变化。
4. 自定义信号强制更新所有任务
新增/修改任务时,通过Django信号触发所有任务的调度更新,避免原有任务被错误标记为已执行:
# 在应用的signals.py中添加 from django.db.models.signals import post_save, post_delete from django.dispatch import receiver from django_celery_beat.models import PeriodicTask, PeriodicTasks @receiver(post_save, sender=PeriodicTask) @receiver(post_delete, sender=PeriodicTask) def refresh_all_tasks(sender, instance, **kwargs): for task in PeriodicTask.objects.exclude(id=instance.id): PeriodicTasks.changed(task)
然后在apps.py中注册信号:
from django.apps import AppConfig class YourAppConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'your_app' def ready(self): import your_app.signals
5. 升级依赖包到最新稳定版
当前使用的Celery、Celery Beat和Django Celery Results版本存在已知的调度器更新逻辑缺陷,升级到最新版可修复多数问题:
pip install --upgrade celery django-celery-beat django-celery-results
6. 调整Postgres事务隔离级别
在Django数据库配置中设置隔离级别为READ COMMITTED,确保Beat能实时读取到数据库中任务的最新状态:
# settings.py中的DATABASES配置 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'your_db', 'USER': 'your_user', 'PASSWORD': 'your_pass', 'HOST': 'localhost', 'PORT': '5432', 'OPTIONS': { 'isolation_level': 'read committed', }, } }
内容的提问来源于stack exchange,提问作者Bhavin Pokal

