やりたいこと
Dockerなどで複数のSidekiqプロセスが立ち上がっている状態でプロセス配下のジョブだけを取得したい
方法
# 実行環境のSidekiqプロセス識別子を取得
process_identity = Sidekiq::JobRetry.new.identity
Sidekiq::Workers.new.each do |process_id, thread_id, job|
# 一致しなければskipする
next unless process_identity == process_id
... # ジョブに対して実行したい処理
end
説明
Sidekiq::Workers.new
で取得できる実行中ジョブは、全Sidekiqプロセスで実行されているジョブが含まれているので、その中から選別する必要がある。
Docker環境でなければ、以下のようにプロセスごとの識別子を取得できる。
Sidekiq::ProcessSet.new.find { |p| p['pid'] == Process.pid }.identity
Docker環境の場合、同一PIDで稼働させていることがあるので、PIDは利用できず、Sidekiq::Util
のクラス変数を直接読みにいく。
Sidekiq::Util
がincludeされているクラスで比較的簡単にインスタンス化できそうなもの(根拠はない)として、Sidekiq::JobRetry
を利用する。
経緯
sidekiq-unique-jobsのuntil_and_while_executing
が通常のSidekiqのプロセス終了時のリトライ処理ではロックの関係でリトライできなかったので、ロック削除したり、enqueueし直したりする必要があった。
Sidekiqのshutdownブロック(config.on(:shutdown)
)にて実行中のジョブに対して処理を実装していたら、複数のdockerコンテナが同時に終了したときに同じジョブが大量にenqueueされて困った。