Работа с celerybeat как с единственной точкой отказа

Я ищу рекомендуемое решение для обхода celerybeat как единой точки отказа для развертывания celery/rabbitmq. Я не нашел ничего, что имело смысл до сих пор, поиск в Интернете.

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

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


person Dmitry Grinberg    schedule 15.02.2012    source источник


Ответы (1)


В репозитории celery github есть открытая проблема по этому поводу. Хотя не знаю, работают ли они над этим.

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

Что-то типа:

if not cache.add('My-unique-lock-name', True, timeout=lock_timeout):
    return

Выяснить время ожидания блокировки очень сложно. Мы используем 0,9 * задача run_every секунды, если разные celerybeats будут пытаться запускать их в разное время. 0.9 просто для того, чтобы оставить некоторый запас (например, когда сельдерей немного отстает от графика один раз, тогда он работает по расписанию, что приведет к тому, что блокировка все еще будет активной).

Затем вы можете использовать экземпляр celerybeat на всех машинах. Каждая задача будет поставлена ​​в очередь для каждого экземпляра celerybeat, но только одна задача завершит выполнение.

Таким образом, задачи по-прежнему будут учитывать run_every — наихудший сценарий: задачи будут выполняться со скоростью 0,9*run_every.

Одна проблема с этим случаем: если задачи были поставлены в очередь, но не обработаны в запланированное время (например, из-за того, что обработчики очереди были недоступны) - тогда блокировка может быть размещена в неподходящее время, что может привести к тому, что 1 следующая задача просто не запустится. Чтобы обойти это, вам понадобится какой-то механизм обнаружения, выполняется ли задача более или менее вовремя.

Тем не менее, это не должно быть обычной ситуацией при использовании в производстве.

Другим решением является подкласс celerybeat Scheduler и переопределение его метода tick. Затем для каждого тика добавляйте блокировку перед обработкой задач. Это гарантирует, что только celerybeats с одинаковыми периодическими задачами не будут ставить одни и те же задачи несколько раз. Только один celerybeat для каждого тика (тот, кто выигрывает условие гонки) будет ставить задачи в очередь. Через один celerybeat падает, со следующим тиком гонку выигрывает другой.

Это, конечно, можно использовать в сочетании с первым решением.

Конечно, для того, чтобы это работало, кэш-бэкэнд должен быть реплицирован и/или разделен для всех серверов.

Это старый вопрос, но я надеюсь, что это поможет любому.

person arkens    schedule 18.10.2012