You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

新增任务后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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 15:16:00