私は自分のサイトを python/django に移植しています。主な演習の 1 つは、ユーザーが現地時間でイベントをスケジュールし、それを毎日実行できる一連のデータに関係しています。
現在、(別のサーバー上に) cron ジョブがあり、たとえば 5 分ごとにメソッドを起動し、次の (たとえば) 10 分で何かをスケジュールする必要があるかどうかを確認します。
時間の値と、各ジョブのユーザーのローカル タイムゾーンを保存します
これを行う最善の方法は何ですか?
現在、次の機能に取り組んでいます。
- サーバー時間をユーザーの現地時間に変換します。
- 「今日」とユーザーが指定した時刻にローカライズされたローカルの日時オブジェクトを作成します
- ユーザーのアラームが鳴ってから 10 分以内かどうかを確認します。
- 23:50 ~ 23:59:59 の間で、ユーザーの設定時刻が 00:00 ~ 00:10 の場合 ローカライズされた「今日」は「明日」の日付で作成されます。(例: 午前 0 時まであと 2 分で、ユーザーが 12:01 にイベントを開催したい場合、明日の日付でイベントを計算します)
- スケジュールされているときに last_scheduled フィールドを設定し、複数回送信しないようにするために last_fired フィールドを設定します。
今から 10 分以内であれば、すぐに起動するタスク (スレッドなど) をスケジュールします。
ここでのベストプラクティスについてはよくわかりません。すべきこと:
将来のタスクがあるかどうかを確認し、短期間のタスクをスケジュールしますか?
事前にすべての時間を事前に生成します (おそらく 1 か月ごと?)
まったく別のことをしますか?
また、いつでも「次の」イベントをスケジュールできると考えていましたが、サーバーがオフラインになり、「次の」イベントを逃した場合、翌日がスケジュールされないのではないかと心配です.
明確にするために:
- ジョブごとに時間とタイムゾーンを保存します (例: 米国/東部の正午)。
- 私は DST を修正しているので、UTC 時間を計算するときは、今日の日付を utc で取得し、現地時間に変換してから、それを使用してデルタを計算します。私は pytz と normalize() を使用して、不安定な DST の問題が発生しないようにしています。
- 二重に実行しないように、最後にスケジュールされ、最後に実行された時刻があります。
以下の解決策を見ると、他の唯一の観察結果は、何らかの理由でスケジュールされた時間を逃した場合、「次」は決して起こらないということだと思います。見逃したアラームを修正するための2番目の機能を作成できると思います。
編集: 以下の答えを理解した後、次のそれほど悪いシナリオを思いつきました:
次のフィールドがあります
- 最終イベント実行時間
- 前回イベントがスケジュールされた時刻
- 次回イベント実行時間
- 時刻とタイムゾーン
次の場合は必ず next_run_time を計算して設定します: イベントを更新するか、イベントを発生させます。これにより、次のことが行われます。
- 最後の実行時間があれば、少なくとも 2 時間先の next_run_time が計算されます (パディングを追加して DST の問題を回避します)。
- イベントが一度も実行されていない場合は、少なくとも 15 分後にスケジュールを設定します (複数の同時スケジュールは避けてください)。
私のスケジュールされたジョブは次のことを行います:
- 次の 15 分間に next_run_time があり、現在スケジュールされていないすべてのイベントをチェックします。一致するものはすべてスケジュールされます。
ジョブのスケジューリング:
- タスクをスケジュールし、ジョブを「今すぐ」スケジュールどおりに設定します
タスクの実行時 (成功):
- last_run_time は「今」に更新されます
- next_run_time が再計算されます
タスクが失敗した場合: - ジョブは 30 秒後に再スケジュールされます。しきい値を超えて失敗した場合 (私の場合は 3 分遅れ)、タスクは中止され、翌日の next_run_time が再計算されます。これはログに記録され、あまり発生しないことを願っています
私のイベントは常に(毎日)であるため、これはほとんどうまくいくようです。