再試行されたサイドキックジョブをキューの先頭に置く
概要
約100000のジョブを含むsidekiqキューがあります。一部のジョブは失敗しますが、sidekiq によって再試行されると通常は成功するため、問題ありません。
ただし、RetrySet からのジョブはキューの最後に追加されます。ジョブが再度処理されるまでに長い時間がかかります。
再試行されたジョブをキューの先頭に置き、優先的に処理されるようにするにはどうすればよいですか?
解決策
私の記憶が正しければ、Sidekiq キューは Redis リストを使用するため、FIFO が期待されるため、これに対する優れた答えはないと思います。再試行されたジョブは同じキューに入れられるため、常に最後にあることになります。
1 つのアプローチは、優れたものではなく、私がお勧めするものでもありませんが、別のキューを追加し、代わりにジョブの再試行をそこに送信することです。
# config/sidekiq.yml
---
:queues:
- default
- my_worker_retries
ワーカーが再試行しないように設定します。
class MyWorker
include Sidekiq::Worker
sidekiq_options retry: false
end
ワーカーが次のようなエラーを予想通りに発生させるようにしてください。
class MyWorker
include Sidekiq::Worker
sidekiq_options retry: false
def perform(arg)
raise ArgumentError
end
end
その例外を処理するロジックを追加し、新しく作成したキューを通じてこのジョブを再度実行します。
class MyWorker
include Sidekiq::Worker
sidekiq_options retry: false
def perform(arg)
begin
raise ArgumentError
rescue ArgumentError => error
MyWorker.set(queue: :my_worker_retries).perform_async(arg)
end
end
end
これは、失敗して my_worker_retries キューに入れられたジョブは無限ループに陥る可能性があることを意味します。ジョブは失敗し、救出され、キューに入れられ、再び失敗します。さらに悪いことに、Sidekiq が構築したキューを利用していないためです。再試行キュー メカニズムには、CPU が処理できる速度で再試行が行われないようにするためのバックオフ アルゴリズムがありません。
全体が脆いだけです。
このジョブが再試行された回数を示す引数を渡すことで、これを防ぐことができます。これにより、特定の回数の後に停止できるようになります。
class MyWorker
include Sidekiq::Worker
sidekiq_options retry: false
MAX_RETRIES = 5
def perform(arg, retries = 0)
raise 'Too many retries' if retries >= MAX_RETRIES
begin
raise ArgumentError
rescue ArgumentError => error
MyWorker.set(queue: :my_worker_retries).perform_async(arg, retries + 1)
end
end
end
これを拡張して、独自のバックオフ アルゴリズムを作成することもできます。
MyWorker.set(queue: :my_worker_retries).perform_in((retries + 1).hours, arg, retries + 1)
これはどれも理想的なものではありませんが、質問には答えます。これよりも良い解決策があることを願っています。
https://github.com/chartmogul/sidekiq-priority_queue など、機能する可能性のある Sidekiq 拡張機能がいくつかありますが、私はこれまでに使用したことがありません。