Techioz Blog

再試行されたサイドキックジョブをキューの先頭に置く

概要

約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 拡張機能がいくつかありますが、私はこれまでに使用したことがありません。