После планирования новой задачи ранее запланированные задачи не выполняются 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_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 оно автоматически создает несколько планировщиков, таких как internet_status_check, system_resource_check и т.д., используя IntervalSchedule.

Сначала все идет гладко, но как только я создаю любой новый планировщик, будь то IntervalSchedule или CrontabSchedule, ранее запущенные планировщики прекращают выполнение. В терминале celery beat также появляется сообщение DatabaseScheduler: Schedule changed.

После этого сообщения он не отправляет ни одного задания на выполнение, даже если задания доступны для выполнения, что можно увидеть из панели администратора Django.

Я попробовал изменить брокер на RabbitMQ и result_backend на Redis/django-db. Но та же проблема сохраняется. Даже если я перезапускаю celery beat, он не выбирает никаких задач.

Единственное, что сработало, это изменение last_run_at для всех задач на None и последующий вызов метода changed() с помощью django shell во время выполнения. Но это не может быть решением проблемы.

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?

Это случилось со мной в первый раз, когда я использовал beat, что усложняет задачу, учитывая, что он не предоставляет никаких ошибок или журналов, чтобы проверить, чего не хватает.

Полагаю, что сначала вы уже настроили rabbitmq и redis. Например, установили хост, v_host, пользователя, пароли и т.д. Я не вижу CELERY_BROKER_URL и CELERY_RESULT_BACKEND, поэтому я предполагаю, что они находятся в вашем settings.py. В моем случае, мой файл celery.py выглядит так:

class Celery(celery.Celery):
  os.environ.setdefault('DJANGO_SETTINGS_MODULE',
                      'project.settings')

  app = Celery(settings.CELERY_APP,
             backend=settings.CELERY_RESULT_BACKEND,
             broker=settings.CELERY_BROKER_URL)
  app.config_from_object('django.conf:settings', namespace='CELERY')
  app.autodiscover_tasks(settings.INSTALLED_APPS)

  app.conf.update(
    CELERYBEAT_SCHEDULE={
    'send_campaign': {
      'task': 'tasks.MyTask',
      'schedule': crontab(minute='*/2'),
      'options': {'queue': 'high'}
    }})

Теперь, чтобы убедиться, что ваш ритм работает с рабочим сельдереем, вы можете использовать эту инструкцию в другом терминале: celery -A proj worker --loglevel=info -B.

Однако вы можете попробовать запустить его после удаления всех отложенных задач с помощью celery -A proj purge или усечения таблиц django_celery_beat_periodictask и django_celery_beat_periodictasks.

Учитывая, что его конфигурация может быть обширной, работа с docker может оказаться полезной. Ознакомьтесь с этой статьей, в которой пошагово рассказывается об этом, чтобы вы могли сравнить конфигурации, которых не хватает в вашей реализации.

После 3 дней изучения проблемы я обнаружил, что проблема связана с настройками часового пояса.

Я установил USE_TZ = False в файле settings.py приложения Django, и если мы не установим DJANGO_CELERY_BEAT_TZ_AWARE=False, Celery Beat установит True по умолчанию.

Итак, настройка DJANGO_CELERY_BEAT_TZ_AWARE=False в settings.py решила проблему.

Вернуться на верх