В репозитории 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