Django Celery: выполнение только одного экземпляра длительного процесса - PullRequest
9 голосов
/ 18 января 2012

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

В соответствии с предыдущей рекомендацией я использую Django Celery для планирования этой длительной задачи.

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

Мой текущий эксперимент выглядит следующим образом: в 8:55 запускается экземпляр задачи.Когда задача заканчивается, она запускает другой экземпляр для запуска в следующие пять минут.Таким образом, если первое задание завершится в 8:57, второе будет выполнено в 9:00.Если первая задача выполняется долго и заканчивается в 9:01, она запланирует запуск следующего экземпляра в 9:05.

Я боролся с множеством загадочных ошибок, когда делал что-то большее, чем простой пример ниже, и я не нашел других примеров людей, планирующих задачи из предыдущего самого экземпляра.Мне интересно, может быть, есть лучший подход к тому, что я пытаюсь сделать.Я знаю, что есть способ назвать свои задачи;возможно, есть способ поиска запущенных или запланированных экземпляров с одинаковыми именами?Есть ли у кого-нибудь какие-либо советы относительно запуска задачи каждые пять минут, но при этом следует убедиться, что одновременно выполняется только одна задача?

Спасибо, Джо

В mymodule / tasks.py:

import datetime
from celery.decorators import task 

@task 
def test(run_periodically, frequency):

    run_long_process()
    now = datetime.datetime.now()
    # Run this task every x minutes, where x is an integer specified by frequency
    eta = (
      now - datetime.timedelta(
         minutes =  now.minute % frequency , seconds = now.second, 
         microseconds = now.microsecond ) ) + datetime.timedelta(minutes=frequency) 
    task = test.apply_async(args=[run_periodically, frequency,], eta=eta)  

Из оболочки ./manage.py:

from mymodule import tasks
result = tasks.test.apply_async(args=[True, 5])

1 Ответ

7 голосов
/ 18 января 2012

Вы можете использовать периодические задачи в паре со специальной блокировкой, которая обеспечивает выполнение задач по одной. Вот пример реализации из документации Celery:

http://ask.github.com/celery/cookbook/tasks.html#ensuring-a-task-is-only-executed-one-at-a-time

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

...