終了したスレッドの process_instances からの削除漏れを修正

rails/solid_queue

Solid Queue 1.3.0以降で発生していた、スレッド終了時の管理データ不整合によるクラッシュが解消されました。replace_thread メソッドが process_instances からエントリを削除しないため、同じ終了スレッドが繰り返し検出され NoMethodError が発生していた問題に対処しています。

背景

Solid Queue 1.3.0で導入された非同期モードにおいて、スレッドが異常終了した際に NoMethodError: undefined method 'instantiate' for nil が発生する問題が報告されていました(#710)。この問題は、スレッド管理の2つのデータ構造である configured_processesprocess_instances の同期が取れていないことが原因でした。

スレッドが終了すると、replace_threadconfigured_processes からエントリを削除していましたが、process_instances には終了したスレッドのエントリが残り続けていました。次の監視ループで check_and_replace_terminated_processes が同じ終了スレッドを再度検出し、replace_thread を呼び出すと、既に削除済みの configured_processes から nil が返されてクラッシュしていました。

技術的な変更

AsyncSupervisor#replace_thread メソッドが、ForkSupervisor#replace_fork と同じパターンに統一されました。

変更前:

def replace_thread(thread_id, instance)
  SolidQueue.instrument(:replace_thread, supervisor_pid: ::Process.pid) do |payload|
    payload[:thread] = instance

    error = Processes::ThreadTerminatedError.new(instance.name)
    release_claimed_jobs_by(instance, with_error: error)

    start_process(configured_processes.delete(thread_id))
  end
end

変更後:

def replace_thread(thread_id)
  SolidQueue.instrument(:replace_thread, supervisor_pid: ::Process.pid) do |payload|
    if (instance = process_instances.delete(thread_id))
      payload[:thread] = instance

      error = Processes::ThreadTerminatedError.new(instance.name)
      release_claimed_jobs_by(instance, with_error: error)

      start_process(configured_processes.delete(thread_id))
    end
  end
end

process_instances.delete(thread_id) を最初に実行し、その戻り値を if 文でガードすることで、エントリが既に削除されている場合は何もしません。これにより、同じ終了スレッドが2回目以降に検出されても安全に処理がスキップされます。

また、replace_thread の引数から instance パラメータが削除され、thread_id のみを受け取るようになりました。呼び出し側の check_and_replace_terminated_processes も対応して変更されています:

terminated_threads.each { |thread_id, _| replace_thread(thread_id) }

設計判断

ForkSupervisor との一貫性 を重視した変更です。PR本文で言及されているように、ForkSupervisor#replace_fork は既に同じパターンを採用していました。プロセスフォーク版とスレッド版の監視機構で、終了したワーカーの置き換えロジックを統一することで、コードの保守性と理解しやすさが向上しています。

process_instances から先に削除する順序も重要です。configured_processes を先に削除すると、process_instances に残ったエントリが次のループで再検出され、今回修正した問題と同じ状況が発生します。削除の原子性を delete の戻り値チェックで保証することで、競合状態に対する防御も実現しています。

まとめ

本PRは、スレッド終了時の管理データ構造の同期を確立した修正です。process_instances からのエントリ削除を追加し、既存の ForkSupervisor と同じガードパターンを適用することで、Solid Queue 1.3.0以降で報告されていたクラッシュを解消しています。プロセスフォーク版とスレッド版の実装を揃えたことで、今後の保守においても一貫性が保たれます。

記事メタデータ

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リンク記法の正確性

ファイル名付きシンタックスハイライト(```ruby:ファイルパス)およびGitHubのIssue番号へのリンク記法([#710](URL))が正しく使用されています。

対象読者への適合性 ✓ PASS

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

Solid Queueの内部実装に関するトピックを、専門用語を適切に用いて解説しており、対象読者であるエンジニアに適合した内容です。

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

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

各セクションが総論→各論の構成で、かつ各パラグラフがトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が徹底されており、可読性が非常に高いです。

Diff内容との照合 ✓ PASS

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

記事内で引用されている変更前後のコードブロック、および関連するコードスニペットは、提供されたDiff情報と正確に一致しています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

`configured_processes`、`process_instances`、`AsyncSupervisor`といった技術用語が、PRの文脈に沿って正確に使用されています。

説明の技術的正確性 ✓ PASS

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

スレッド終了時にデータ不整合が発生する根本原因と、その解決策(`process_instances`からの削除とガード節の追加)に関する説明が、技術的に正確かつ論理的です。

事実の突合 ✓ PASS

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

記事内のすべての主張(クラッシュの原因、`ForkSupervisor`との一貫性など)は、PRのDescriptionやDiff内容によって裏付けられており、ハルシネーションは検出されませんでした。

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

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

PR番号(#714)やIssue番号(#710)、バージョン番号(1.3.0)などの数値・固有名詞はすべて正確に記載されています。

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

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

記事のタイトル「終了したスレッドの process_instances からの削除漏れを修正」は、PRの主題「Clean up dead thread from process_instances when replacing it」を的確に反映しています。

外部知識の正確性 ✓ PASS

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

バージョン番号「1.3.0」はPR Descriptionに直接記載はありませんが、PRが修正対象とするIssue(#710)に明記されており、PRの文脈に含まれる情報です。不適切な外部知識の追加はありません。

時間表現の正確性 ✓ PASS

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

PR内の「already used」という表現を「既に同じパターンを採用していました」と正しく過去形で表現するなど、時間表現は正確です。