Периодическая задача Django celerybeat запускается только один раз

Я пытаюсь запланировать задачу, которая запускается каждые 10 минут, используя Django 1.9.8, Celery 4.0.2, RabbitMQ 2.1.4, Redis 2.10.5. Все они работают в контейнерах Docker в Linux (Fedora 25). Я пробовал много комбинаций вещей, которые я нашел в документах Celery и на этом сайте. Единственная комбинация, которая работала до сих пор, приведена ниже. Однако периодическая задача запускается только при запуске приложения, но после этого расписание игнорируется. Я полностью подтвердил, что запланированная задача не запускается снова после первоначального времени.

Моя (почти рабочая) установка, которая запускается только один раз:

настройки.py:

INSTALLED_APPS = (
   ...
   'django_celery_beat',
   ...
)
BROKER_URL = 'amqp://{user}:{password}@{hostname}/{vhost}/'.format(
    user=os.environ['RABBIT_USER'],
    password=os.environ['RABBIT_PASS'],
    hostname=RABBIT_HOSTNAME,
    vhost=os.environ.get('RABBIT_ENV_VHOST', '')

# We don't want to have dead connections stored on rabbitmq, so we have to negotiate using heartbeats
BROKER_HEARTBEAT = '?heartbeat=30'
if not BROKER_URL.endswith(BROKER_HEARTBEAT):
    BROKER_URL += BROKER_HEARTBEAT

BROKER_POOL_LIMIT = 1
BROKER_CONNECTION_TIMEOUT = 10

# Celery configuration

# configure queues, currently we have only one
CELERY_DEFAULT_QUEUE = 'default'
CELERY_QUEUES = (
    Queue('default', Exchange('default'), routing_key='default'),
)

# Sensible settings for celery
CELERY_ALWAYS_EAGER = False
CELERY_ACKS_LATE = True
CELERY_TASK_PUBLISH_RETRY = True
CELERY_DISABLE_RATE_LIMITS = False

# By default we will ignore result
# If you want to see results and try out tasks interactively, change it to False
# Or change this setting on tasks level
CELERY_IGNORE_RESULT = True
CELERY_SEND_TASK_ERROR_EMAILS = False
CELERY_TASK_RESULT_EXPIRES = 600

# Set redis as celery result backend
CELERY_RESULT_BACKEND = 'redis://%s:%d/%d' % (REDIS_HOST, REDIS_PORT, REDIS_DB)
CELERY_REDIS_MAX_CONNECTIONS = 1

# Don't use pickle as serializer, json is much safer
CELERY_TASK_SERIALIZER = "json"
CELERY_RESULT_SERIALIZER = "json"
CELERY_ACCEPT_CONTENT = ['application/json']
CELERYD_HIJACK_ROOT_LOGGER = False
CELERYD_PREFETCH_MULTIPLIER = 1
CELERYD_MAX_TASKS_PER_CHILD = 1000

celeryconf.py

coding=UTF8
from __future__ import absolute_import
import os
from celery import Celery
from django.conf import settings

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "web_portal.settings")
app = Celery('web_portal')
CELERY_TIMEZONE = 'UTC'
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

задачи.py

from celery.schedules import crontab
from .celeryconf import app as celery_app

@celery_app.on_after_finalize.connect
def setup_periodic_tasks(sender, **kwargs):
    # Calls email_scanner every 10 minutes
    sender.add_periodic_task(
        crontab(hour='*', 
                minute='*/10', 
                second='*', 
                day_of_week='*',  
                day_of_month='*'),
        email_scanner.delay(),
    )

@app.task
def email_scanner():
    dispatch_list = scanning.email_scan()
    for dispatch in dispatch_list:
        validate_dispatch.delay(dispatch)
    return

run_celery.sh — используется для запуска задач сельдерея из docker-compose.yml

#!/bin/sh

# wait for RabbitMQ server to start
sleep 10

cd web_portal
# run Celery worker for our project myproject with Celery configuration stored in Celeryconf
su -m myuser -c "celery beat -l info --pidfile=/tmp/celerybeat-web_portal.pid -s /tmp/celerybeat-schedule &"
su -m myuser -c "celery worker -A web_portal.celeryconf -Q default -n default@%h"

Я также пытался использовать CELERYBEAT_SCHEDULER в settings.py вместо декоратора @celery_app.on_after finalize_connect и блокировать в tasks.py, но планировщик ни разу не запускался.

settings.py (не работает вообще сценарий)

(то же, что и раньше, кроме включения следующего)

CELERYBEAT_SCHEDULE = {
    'email-scanner-every-5-minutes': {
        'task': 'tasks.email_scanner',
        'schedule': timedelta(minutes=10)
    },
}

Онлайн-документация Celery 4.0.2 предполагает, что я должен инстинктивно знать многие данные, но я новичок в этой среде. Если кто-нибудь знает, где я могу найти учебник, КРОМЕ docs.celeryproject.org и http://django-celery-beat.readthedocs.io/en/latest/, которые предполагают, что я уже являюсь мастером Django, я был бы признателен. Или, конечно, дайте мне знать, если вы видите что-то явно неправильное в моей настройке. Спасибо!


person Tracy Martin    schedule 20.02.2017    source источник


Ответы (1)


Я нашел решение, которое работает. Мне не удалось заставить работать CELERYBEAT_SCHEDULE или декораторы задачи celery, и я подозреваю, что это может быть, по крайней мере частично, связано с тем, как я запустил задачу Beat Celery.

Рабочее решение проходит целых 9 ярдов, чтобы использовать Django Database Scheduler. Я скачал проект GitHub "https://github.com/celery/django-celery-beat» и включил весь код в качестве еще одного «приложения» в свой проект. Это позволило Django-Admin получить доступ к таблицам cron / interval / периодических задач через браузер. Я также изменил свой run_celery.sh следующим образом:

#!/bin/sh

# wait for RabbitMQ server to start
sleep 10
# run Celery worker for our project myproject with Celery configuration stored in Celeryconf
celery beat -A web_portal.celeryconf -l info --pidfile=/tmp/celerybeat- web_portal.pid -S django --detach
su -m myuser -c "celery worker -A web_portal.celeryconf -Q default -n default@%h -l info "

После добавления запланированной задачи через веб-интерфейс django-admin планировщик заработал нормально.

person Tracy Martin    schedule 21.02.2017