Настройка периодических задач в сельдерее (celerybeat) динамически с помощью add periodic task

я использую Celery 4.0.1 С Django 1.10 и у меня проблемы с планированием задач (запуск задачи работает нормально). Вот конфигурация сельдерея:

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myapp.settings')
app = Celery('myapp')

app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

app.conf.BROKER_URL = 'amqp://{}:{}@{}'.format(settings.AMQP_USER, settings.AMQP_PASSWORD, settings.AMQP_HOST)
app.conf.CELERY_DEFAULT_EXCHANGE = 'myapp.celery'
app.conf.CELERY_DEFAULT_QUEUE = 'myapp.celery_default'
app.conf.CELERY_TASK_SERIALIZER = 'json'
app.conf.CELERY_ACCEPT_CONTENT = ['json']
app.conf.CELERY_IGNORE_RESULT = True
app.conf.CELERY_DISABLE_RATE_LIMITS = True
app.conf.BROKER_POOL_LIMIT = 2

app.conf.CELERY_QUEUES = (
    Queue('myapp.celery_default'),
    Queue('myapp.queue1'),
    Queue('myapp.queue2'),
    Queue('myapp.queue3'),
)

затем в tasks.py у меня есть:

@app.task(queue='myapp.queue1')
def my_task(some_id):
    print("Doing something with", some_id)

In views.py я хочу запланировать эту задачу:

def my_view(request, id):
    app.add_periodic_task(10, my_task.s(id))

затем я выполняю команды:

sudo systemctl start rabbitmq.service
celery -A myapp.celery_app beat -l debug
celery worker -A myapp.celery_app

но задача не запланирована. Я ничего не вижу в журналах. Задача работает, потому что, на мой взгляд, я делаю:

def my_view(request, id):
    my_task.delay(id)

в задача выполнена.

если в моем файле конфигурации, если я запланирую задачу вручную, как это работает:

app.conf.CELERYBEAT_SCHEDULE = {
    'add-every-30-seconds': {
        'task': 'tasks.my_task',
        'schedule': 10.0,
        'args': (66,)
    },
}

Я просто не могу запланировать динамически задач. Есть идеи?

1 ответов


На самом деле вы не можете не определить периодическую задачу на уровне представления, потому что настройка расписания ударов будет загружена первой и не может быть перенесена во время выполнения:

The add_periodic_task() функция добавит запись в настройку beat_schedule за кулисами, и та же настройка также может использоваться для настройки периодических задач вручную:

app.conf.CELERYBEAT_SCHEDULE = {
    'add-every-30-seconds': {
        'task': 'tasks.my_task',
        'schedule': 10.0,
        'args': (66,)
    },
}

что означает, если вы хотите использовать add_periodic_task() он должен быть обернут в on_after_configure обработчик на уровне приложения сельдерей и любые изменения во время выполнения не вступят в силу:

app = Celery()

@app.on_after_configure.connect
def setup_periodic_tasks(sender, **kwargs):
    sender.add_periodic_task(10, my_task.s(66))

как говорится в doc обычный celerybeat просто отслеживать выполнение задачи:

планировщиком по умолчанию является celery.beat.PersistentScheduler, который просто отслеживает время последнего выполнения в локальном файле базы данных shelve.

для того, чтобы иметь возможность динамически управлять периодическими задачами и перенести celerybeat в время выполнения:

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

задачи будут сохранены в базе данных в Django и планировщик может быть обновлен в модели задач на уровне БД. Всякий раз, когда вы обновляете периодическую задачу, счетчик в этой таблице задач будет увеличиваться и сообщает сельдерею beat service для перезагрузки расписания из базы данных.

возможное решение для вас может быть следующим:

from django_celery_beat.models import PeriodicTask, IntervalSchedule

schedule= IntervalSchedule.objects.create(every=10, period=IntervalSchedule.SECONDS)
task = PeriodicTask.objects.create(interval=schedule, name='any name', task='tasks.my_task', args=json.dumps([66]))

views.py

def update_task_view(request, id)
    task = PeriodicTask.objects.get(name="task name") # if we suppose names are unique
    task.args=json.dumps([id])
    task.save()


EDIT: (13/01/2018)


последние релиз 4.1.0 затронули тему в этом билет № 3958 и был объединен