После планирования новой задачи ранее запланированные задачи не выполняются 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 решила проблему.