これについて、セロリの github リポジトリに未解決の問題があります。彼らがそれに取り組んでいるかどうかはわかりません。
回避策として、特定の PeriodicTask の 1 つのインスタンスのみが一度に実行されるように、タスクのロックを追加できます。
何かのようなもの:
if not cache.add('My-unique-lock-name', True, timeout=lock_timeout):
return
ロックのタイムアウトを把握するのは、かなりトリッキーです。異なる celerybeats が異なる時間にそれらを実行しようとする場合、0.9 * task run_every 秒を使用しています。わずかなマージンを残すためだけに 0.9 を使用します (たとえば、セロリがスケジュールより少し遅れている場合、スケジュールどおりであり、ロックが引き続きアクティブになる可能性があります)。
その後、すべてのマシンで celerybeat インスタンスを使用できます。各タスクはすべての celerybeat インスタンスのキューに入れられますが、実行を終了するのはそのうちの 1 つのタスクだけです。
タスクはこの方法でも run_every を尊重します - 最悪のシナリオ: タスクは 0.9*run_every の速度で実行されます。
この場合の 1 つの問題: タスクがキューに入れられたが、スケジュールされた時間に処理されなかった場合 (たとえば、キュー プロセッサが使用できないため)、ロックが間違った時間に設定される可能性があり、次の 1 つのタスクが実行されない可能性があります。これを回避するには、タスクが時間どおりかどうかにかかわらず、何らかの検出メカニズムが必要になります。
それでも、本番環境で使用する場合、これは一般的な状況ではありません。
別の解決策は、celerybeat Scheduler をサブクラス化し、その tick メソッドをオーバーライドすることです。次に、ティックごとに、タスクを処理する前にロックを追加します。これにより、同じ定期的なタスクを持つ celerybeats のみが、同じタスクを複数回キューに入れないようになります。ティックごとに 1 つの celerybeat (競合状態に勝った人) だけがタスクをキューに入れます。ある celerybeat でダウンし、次のティックで別の 1 つがレースに勝ちます。
もちろん、これは最初のソリューションと組み合わせて使用 できます。
もちろん、これを機能させるには、すべてのサーバーでキャッシュ バックエンドを複製および/または共有する必要があります。
これは古い質問ですが、誰かの役に立てば幸いです。