Avoid race condition in connection maintenance thread during leak check

rails/rails

この修正は、接続プールの保守スレッドとリークチェックスレッド間で発生していた競合状態を明示的に同期させ、テストの不安定さを解消します。

背景

test_check_connection_leaks_does_not_report_connections_held_for_async_reape... は、reaper_lock 内で保守作業中の接続がリークとして誤検知されないことを検証するテストです。PR #57744 では、非同期実行環境下で保守作業が完了するまで待機させることでフラークを防ごうとしましたが、結果として別のレースが発生しテストが再び不安定になりました。今回の PR は、その新たなレースを解消するためにテストコードに同期ポイントを追加しています。

技術的な変更

追加された同期オブジェクト

maintenance_started = Concurrent::Event.new

Concurrent::Event はスレッド間で「開始」を通知できるシンプルな同期プリミティブです。保守処理が開始した瞬間に maintenance_started.set が呼び出され、テスト側は maintenance_started.wait でその完了を待ちます。

保守ブロック内部でのシグナル送信

pool.send(:sequential_maintenance, ->(candidate) { candidate.equal?(conn) }) do
  maintenance_started.set
  release_maintenance.wait
end

保守スレッドが対象接続を検出した直後にシグナルを送ることで、テストは「保守が実際にチェックアウトを行った」ことを確実に把握できます。

テスト側での待機順序の変更

maintenance_started.wait
assert_predicate conn, :in_use?

従来は wait_for(message: ..., timeout: 1) { conn.in_use? } で暗黙的にポーリングしていましたが、ここでは明示的にシグナル待ちを行い、続いて assert_predicate conn, :in_use? によって接続が使用中であることを確認します。これにより、保守スレッドが接続を取得する前にテストがアサートを実行する可能性が排除されます。

設計判断

テストコードのみでレースを防止するという選択は、実装コードに変更を加えずにテストの信頼性を高めるという方針に沿っています。Concurrent::Event を用いた明示的同期は、スレッド間の順序を保証しつつ、テスト以外の動作に影響を与えません。さらに、assert_predicate を使用したシンプルなアサーションに置き換えることで、テストの可読性と意図が明確になります。これらの変更は、保守スレッドのロジックそのものを変更せず、テスト環境だけで安全にレース条件を除去する実装パターンの一例です。

まとめ

今回の修正は、保守スレッドとリークチェックスレッド間の競合を Concurrent::Event による同期 で排除し、テストのフラークを根本的に解消します。テストコードのみに限定した調整であり、実装やパフォーマンスへの副作用はありません。結果として、接続プールの保守ロジックを安全に検証できる信頼性の高いテストが提供されます。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
9dba6c08

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

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

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

リード文、背景、技術的な変更、設計判断(任意)とまとめが全て揃っており、総論→各論→結論の構成が明確です。

カスタムMarkdown構文 ✓ PASS

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

コードブロックは ```:言語:ファイルパス`` の形式で正しく記述され、GitHubリンクも短縮コミットID・PR番号・Issue番号ともに正しい記法です。

対象読者への適合性 ✓ PASS

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

対象はRails開発者向けのエンジニアで、専門用語の説明は適切であり、初心者向けの余計な解説はありません。

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

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

各セクションは総論パラグラフ→各論パラグラフ→結論パラグラフの流れになっており、段落は1文で要点が示され、長すぎる段落や複数トピックの混在はありません。

Diff内容との照合 ⚠ WARNING

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

コード内容はDiffと一致していますが、記事内のファイルパスが `test/activerecord/cases/test_case_test.rb` となっており、Diffの実際のパス `activerecord/test/cases/test_case_test.rb` と不一致です。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

使用されている技術用語(Concurrent::Event、assert_predicate など)はPRで記載されたものと一致し、誤用はありません。

説明の技術的正確性 ✓ PASS

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

技術的な主張はDiffに示された変更と合致しており、因果関係も正しく説明されています。

事実の突合 ✓ PASS

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

記事の全ての主張はPRタイトル・説明・Diffで裏付けられており、架空の数値や外部知識の追加はありません。

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

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

PR番号 (#57750) のみが記載されており、正確です。

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

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

記事タイトルはPRタイトル「Avoid racing the maintenance thread's checkout」の意味を正確に伝えており、内容と一致しています。

外部知識の正確性 ✓ PASS

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

バージョンサポートやリリース日程等の外部知識は一切含まれていません。

時間表現の正確性 ✓ PASS

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

時間表現の歪曲はなく、PRの記述と一致しています。