Closed5

Rails で特定の Job だけリトライを無効化する

snakasnaka

前提

  • Rails 6.1.x 系
  • Sidekiq 6.5.x 系
snakasnaka

ActiveJob の機能を使う方法

discard_on を使う

以下の例だと、 ActiveJob::DeserializationError という例外が発生した場合それを握り潰して Job のリトライは行わない、という挙動になる。

class SearchIndexingJob < ActiveJob::Base
  discard_on ActiveJob::DeserializationError

  def perform(record)
    # Will raise ActiveJob::DeserializationError if the record can't be deserialized
  end
end

retry_on を使う

以下の例では、ActiveRecord::Deadlocked が発生したときにJobリトライが行われ、Jobの試行回数は最大3回行うことになる。

class RemoteServiceJob < ActiveJob::Base
  retry_on ActiveRecord::Deadlocked, attempts: 3

  def perform(*args)
    # Might raise ActiveRecord::Deadlocked when a local db deadlock is detected
  end
end

この試行回数を 1 以下の数字にすることでリトライを防ぐことができる

  retry_on ActiveRecord::Deadlocked, attempts: 0

ここで注意なのは「Jobの試行回数」であり「リトライ回数」ではないこと

https://zenn.dev/socialplus/articles/1e5bfa2619ec55

snakasnaka

ActiveJob の罠

Job 実行のバックエンドに Sidekiq を利用している場合、 Sidekiq のリトライ機構が Active Job のそれとは別に機能していることに注意が必要である。

たとえば、以下のように rescue_from で例外を捕捉して共通処理を行って例外を raise し直すようなロジックを書いていると、そこから raise された例外は Sidekiq によって捕捉され、そのリトライ機構によってリトライされてしまう。

class RemoteServiceJob < ActiveJob::Base
  retry_on ActiveRecord::Deadlocked, attempts: 0

  rescue_from StandardError do |e|
    # なにか処理
    raise e  # ココで送出された例外は Sidekiq によって捕捉されてしまう
  end

  def perform(*args)
    # Might raise ActiveRecord::Deadlocked when a local db deadlock is detected
  end
end

snakasnaka

Sidekiq の機能を使う

前述のように Sidekiq で例外が捕捉された場合にそれを無視したい。そのようなときは Sidekiq options というものが Job 単位で設定することができる。

https://github.com/sidekiq/sidekiq/wiki/Advanced-Options#jobs

以下の Job では StandardError を捕捉して「なにか処理」を行った後例外を送出し直しているが、retry: false であるため Sidekiq によるリトライは行われない。

class RemoteServiceJob < ActiveJob::Base
  sidekiq_options retry: false

  rescue_from StandardError do |e|
    # なにか処理
    raise e  # ココで送出された例外は Sidekiq によって捕捉されてしまう
  end

  def perform(*args)
    # Might raise ActiveRecord::Deadlocked when a local db deadlock is detected
  end
end
snakasnaka

Jobで例外が出たらリトライせず即時 Dead Job Queue に入れる

上の例だと、Jobが失敗したという事実が Sidekiq の Web UI から事後的に確認することができず、場合によっては問題があるかもしれない。

失敗した Job を Dead Job Queue に入れる場合は retry: 0 のように設定する。

-  sidekiq_options retry: false
+  sidekiq_options retry: 0

そうすることで、Sidekiq WebUI の Dead Job Queue で失敗した Job を事後に確認することができる。

このスクラップは2025/03/09にクローズされました