1

私は自分のサイトを 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 分後にスケジュールを設定します (複数の同時スケジュールは避けてください)。

私のスケジュールされたジョブは次のことを行います:

  1. 次の 15 分間に next_run_time があり、現在スケジュールされていないすべてのイベントをチェックします。一致するものはすべてスケジュールされます。

ジョブのスケジューリング:

  • タスクをスケジュールし、ジョブを「今すぐ」スケジュールどおりに設定します

タスクの実行時 (成功):

  • last_run_time は「今」に更新されます
  • next_run_time が再計算されます

タスクが失敗した場合: - ジョブは 30 秒後に再スケジュールされます。しきい値を超えて失敗した場合 (私の場合は 3 分遅れ)、タスクは中止され、翌日の next_run_time が再計算されます。これはログに記録され、あまり発生しないことを願っています

私のイベントは常に(毎日)であるため、これはほとんどうまくいくようです。

4

2 に答える 2

3

(私はこれをコメントとして入れますが、SOは新しいユーザーには許可していません)セロリも見てください

于 2013-06-30T01:04:30.923 に答える
2

私の専門分野ではないので、Python/Django の詳細については触れません。ただし、一般に、説明しているタイプのタスクスケジューラは次のように動作する必要があります(IMHO):

  • スケジュール定義を実行時間から分離する
  • スケジュール定義は、ユーザーの現地時間で定義し、タイム ゾーン ID を含める必要があります。
  • 実行時間は UTC である必要があります。
  • タスクが実行されると、スケジュールから次の実行時間を計算する必要があります。

例を見てみましょう。

  • ユーザーは、「米国東部時間で毎晩深夜に実行する」と言います。
  • 「毎日、00:00」のスケジュールを保存しAmerica/New_Yorkます。
  • 最初の実行時間を と計算します2013-06-30T04:00:00Z
  • 任意のメカニズムを使用して、実行時にジョブを実行します。実行する必要があるジョブを定期的にポーリングしている場合は、時間が経過したかどうかを確認してください (ExecTime <= utcnow)。イベント システムや cron ジョブなどを利用できる場合は、そのほうがよいでしょう。
  • ジョブの実行時に、スケジュールを使用して次回の実行時間を計算します。

なぜ現地時間でスケジュールするのですか? 東部時間の場合、夏時間のため、UTC から -5 時間から -4 時間の間で移行します。スケジュールが厳密に UTC ベースである場合、DST 移行後に、ユーザーが間違った時間であると認識した時刻にジョブが実行されていることがわかります。

また、失敗や再試行などの処理について考える必要があります。また、スケジュールされた実行ごとにジョブを複数回実行したくないため、複数ある場合は「処理中」としてマークする方法が必要になる場合があります。タスクをチェックするプログラム。複数のワーカー プロセスが同じタスクを取得しないようにするために、より複雑なロック戦略が必要になる場合があります。これは、ここに書くことができる範囲を少し超えています。

また、夏時間への移行によって発生する現地時間のあいまいさをどのように処理するかについても検討する必要があります。「フォールバック」スタイルのトランジションについて考えてみると、ユーザーが「毎晩午前 1 時 30 分」に実行するように言っていて、1 年に 1 時 30 分が 2 回発生する夜がある場合、何をしたいですか? 特別なことを何もしなければ、最初の発生時に実行されます。これは通常、夏時間です。ユーザーは標準時間を期待している可能性があるため、これを確認する必要がある場合があります。真夜中に走ったとしても、この決定を免除されるわけではありません。真夜中のストロークで移行を行うタイムゾーンがいくつかあります (たとえば、ブラジル)。

これらすべてが面倒だと思われる場合は、既に作成されているジョブ スケジューラを探してみてください。たとえば、Java 上のQuartz 、または.Net スタック上のQuartz.Netです。私はこれに直接精通しているわけではありませんが、検索するとAPScheduler for Python が見つかりました。これはかなり似ています。

于 2013-06-29T22:37:40.190 に答える