TLDR:
これをジョブメソッドの先頭に置きます:
begin
term_now = false
old_term_handler = trap 'TERM' do
term_now = true
old_term_handler.call
end
と
これが少なくとも 10 秒に 1 回呼び出されることを確認します。
if term_now
puts 'told to terminate'
return true
end
と
メソッドの最後に、これを入れます:
ensure
trap 'TERM', old_term_handler
end
説明:
私は同じ問題を抱えていて、この Heroku articleに出会いました。
ジョブには外側のループが含まれていたので、記事に従って と を追加しましtrap('TERM')
たexit
。ただしdelayed_job
、それをピックアップしfailed with SystemExit
、タスクを失敗としてマークします。
がSIGTERM
トラップされるとtrap
、ワーカーのハンドラーは呼び出されず、代わりにすぐにジョブを再開しSIGKILL
、数秒後に取得します。振り出しに戻って。
私はいくつかの代替案を試しましたexit
:
私の最終的な解決策は、回答の上部にあるもので、次の 3 つの部分で構成されています。
'TERM'
潜在的に長いジョブを開始する前に、trap
(Heroku の記事で説明されているように) を実行して新しい割り込みハンドラーを追加し、それを使用して を設定しterm_now = true
ます。
しかしold_term_handler
、遅延ジョブ ワーカー コードセット ( によって返されるtrap
)も取得して、覚えておく必要がcall
あります。
Delayed:Job:Worker
制御をクリーンアップしてシャットダウンするのに十分な時間でに戻す必要があるためterm_now
、少なくとも 10 秒ごとreturn
にtrue
.
ジョブが成功したと見なされるかどうかに応じて、またはどちらreturn true
かを選択できます。return false
最後に、ハンドラーを削除し、Delayed:Job:Worker
終了したらハンドラーを再度インストールすることを忘れないでください。これを行わないと、追加した参照へのダングリング参照が保持され、その上に別の参照を追加するとメモリ リークが発生する可能性があります (たとえば、ワーカーがこのジョブを再度開始した場合)。