5分ごとにタスクを実行するためのcronジョブ設定があります。ただし、タスクの実行に5分以上かかる場合があるため、そのタスクの別のコピーがcronによって同時に実行されます。別のコピーを実行する前に、他のジョブが終了するのを待つようにする方法はありますか?
5 に答える
AFAIKこれは、それ自体を使用して行うことはできませんが、スクリプトで処理できます。これは、次のいずれかの解決策で実行できます
これをデータベースで処理するには、ジョブの開始時に設定され、ジョブの終了時にクリアされるフラグ(または開始時刻、終了時刻、成功ステータスなどの情報)を使用します。ジョブが開始するたびにこのフラグをチェックして、前のジョブが完了したかどうかを確認します。か否か; ただし、フラグをクリアする前にプロセスが停止したかのように例外を処理するようにしてください。他のプロセスは実行できなくなります。
一時ファイルを作成し、現在のプロセスに対して排他ロックを設定することで、OSをフラグとして機能させることができます。これにより、現在のプロセスが終了するまで、他のプロセスがこのファイルに対して排他ロックを設定できなくなります。プロセスが終了すると、ロックが解除され、他のプロセスが機能します。これを含めるには、これがcronジョブの最上位です
file = File.new("cron.lock", "a") can_lock = file.flock(File::LOCK_EX | File::LOCK_NB) if can_lock == false exit 1 else #do whatever you want end
2番目の方法の利点は、プロセスが予期せず終了した場合でも、OSによってロックが自動的に解放されることです。
私の場合、前のプロセスが終了したか、特定の制限時間より長くかかった場合に別のプロセスを開始する必要があるため、最初の方法を選択しました
詳細については、このリンクを確認してください
ファイルシステムまたはデータベースのロックを使用する
cron などを使用して重複を防ぐことはできませんが、少なくとも直接ではありませんが、いくつかの選択肢があります。新しいタスクを生成する前に実行中のタスクのプロセス リストを確認できますが、これは依然として競合状態の影響を受けやすくなっています。いくつかのより良い選択肢は次のとおりです。
- シェル スクリプトでセマフォまたはファイル ロックを使用します。flockとlockfileは、この目的に最適なシェル ユーティリティです。
- cron ジョブにデータベースへの変更が含まれる場合は、行レベルのロックが設定されたテーブルまたはセマフォ列を使用して、別のプロセスの実行中に変更が行われないようにします。
- cron ジョブの間隔を長くして、プロセスが次の実行までに完了するようにします。他のオプションのいずれかを使用する場合でも、これはおそらく良い考えです。
- 同時操作が互いに影響を与えないように、スクリプトを冪等にします。
- キューまたはシングルトン プロセスが cron ジョブよりも適切なオプションであるかどうかを確認してください。
この種の問題に対する完璧な答えはありません。多くは、スクリプトが何をしているか、およびシステムの全体的なアーキテクチャに依存します。あなたの走行距離は異なります。
最良のオプションはあらゆる種類のロック (ファイル、データベースなどを使用) だと思いますが、ロックを使用している場合は、プロセスに非常に巧妙にエラー処理を実装する必要があります。プロセスをもう一度。
使用法 script_with_lock 'script_name'、ロック: 'lock_name'
job_type :script_with_lock, "cd :path && :environment_variable=:environment flock -n /var/lock/:lock.lock bundle exec script/:task :output"
使用法 runner_with_lock 'ruby コード'、ロック: 'lock_name'
job_type :runner_with_lock, "cd :path && flock -n /var/lock/:lock.lock script/rails runner -e :environment ':task' :output"