クラス削除後のジョブに対する並行制御をスキップ

rails/solid_queue

Solid Queueは、ジョブクラスが削除された場合でも並行制御をバイパスし、キュー全体のブロックを防ぐようになりました。これにより、デプロイ時にジョブクラスを削除しても、エンキューされていた該当ジョブが他のジョブの処理を妨げなくなります。

背景

リファクタリングやデプロイによってジョブクラスがコードベースから削除された場合、並行制御キー(concurrency_key)を持つエンキュー済みジョブがワーカーをクラッシュさせる問題がありました。#522 で報告されたこのケースでは、スケジュール実行時に並行制御の取得を試みる際、job_classnil であるにもかかわらず concurrency_limited?true を返し、concurrency_limitconcurrency_duration へのデリゲーションで NoMethodError が発生していました。

この問題はキュー全体をブロックします。ワーカープロセスがクラッシュし、スーパーバイザーが再起動を繰り返すため、該当ジョブより後続のスケジュール済みジョブがすべて処理できなくなります。削除されたクラスのジョブを手動で削除することで解決できますが、より防御的な動作が求められていました。

技術的な変更

concurrency_limited? メソッドに job_class の存在チェックが追加されました。これにより、ジョブクラスが存在しない場合は並行制御を完全にバイパスします。

変更前:

def concurrency_limited?
  concurrency_key.present?
end

変更後:

def concurrency_limited?
  concurrency_key.present? && job_class.present?
end

concurrency_key だけでなく job_class も存在する場合のみ並行制御が適用されます。ジョブクラスが削除されたジョブは通常のジョブとして処理され、ActiveJob::Base.executeNameError が発生し、FailedExecution レコードとして記録されます。

テストコードでは、以下の3つのシナリオが追加されました:

  • 削除されたクラスのジョブが実行時に NameError で失敗し、FailedExecution が作成されること
  • 並行制御キーを持つ削除されたクラスのジョブも同様に失敗すること
  • 並行制御キーを持つ削除されたクラスのジョブが並行制御をスキップし、BlockedExecutionSemaphore レコードを作成しないこと
test "dispatch job with missing class and concurrency key skips concurrency controls" do
  job = create_job_with_missing_class(concurrency_key: "test_key")

  assert_not job.concurrency_limited?

  job.prepare_for_execution

  assert job.reload.ready?
  assert_equal 0, SolidQueue::BlockedExecution.where(job_id: job.id).count
  assert_equal 0, SolidQueue::Semaphore.where(key: "test_key").count
end

設計判断

並行制御を完全にスキップする方式 が採用されました。

ジョブクラスが存在しない場合、並行制御のロジックを実行しようとしてもエラーが発生するだけです。concurrency_limitconcurrency_duration などのメソッドは job_class にデリゲートしており、nil に対する呼び出しは必ず失敗します。並行制御をスキップすることで、これらのジョブを通常のジョブとして扱い、実行時の NameError によって適切に失敗させることができます。

このアプローチにより、以下の3つの利点が得られます:

  • キュー全体のブロックを防止し、他のジョブの処理を継続できる
  • FailedExecution レコードとして問題を記録し、デバッグが可能になる
  • ワーカープロセスのクラッシュと再起動の無限ループを回避できる

本PRは、ジョブクラスの削除というオペレーショナルなミスに対する防御機構を提供します。concurrency_limited? の条件に1つのチェックを追加するだけで、キュー全体のブロックという致命的な問題を回避し、個々のジョブの失敗として適切に処理できるようになりました。

記事メタデータ

Generated by:
Claude Sonnet 4.5 for DiffDaily

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文(総論)→背景・技術詳細(各論)→まとめ(結論)という構成が明確で、読者が変更の全体像を理解しやすい構造になっています。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライト(```言語:ファイルパス)およびGitHubのPR・Issueへのリンク記法が正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

専門用語を適切に使用し、冗長な説明を省くことで、専門知識を持つエンジニアという対象読者に適した内容になっています。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが「総論→各論」で構成され、各段落がトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が守られており、非常に高い可読性を実現しています。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内で引用されているコードブロックは、提供されたDiff情報と完全に一致しており、変更点を正確に反映しています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「concurrency_key」「FailedExecution」などの専門用語が、PRの文脈に沿って正確に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

「job_classがnilの場合にNoMethodErrorが発生する」という問題の原因や、「NameErrorで失敗しFailedExecutionになる」という変更後の挙動について、技術的に正確な説明がなされています。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内のすべての主張は、PRのDescriptionやDiff内のコードで裏付けられており、ハルシネーション(捏造)は見られません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#717)およびIssue番号(#522)が正確に記載され、リンクされています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトル「クラス削除後のジョブに対する並行制御をスキップ」は、PRのタイトル「Skip concurrency controls for jobs whose class has been removed」の内容を的確に要約しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事の内容は提供されたPR情報に限定されており、バージョンサポート状況など、PR外の知識の追記や捏造はありません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

「〜ようになりました」といった表現が、このPRによって変更が適用された事実を正確に伝えており、時間表現の歪曲はありません。