非同期リエーパー処理完了を待機して接続リークチェックを正確化

rails/rails

ActiveRecord の接続リーク検出ロジックが、非同期リエーパーが存在する環境でも正確に動作するよう、メンテナンス完了を待機する処理を追加しました。これにより、リエーパーの非同期タスクが残っている間に発生する誤検知が防がれます。

背景

非同期リエーパー が構成されているテスト環境では、reaper_lock は作業のキューイングのみを保護し、実際のメンテナンスタスクは別スレッドで実行されます。その結果、check_connection_leaks がロック直後に接続状態を確認すると、まだ完了していない非同期タスクが所有する接続が残っていることがあり、誤ってリークと判定されるケースがありました。

この問題は、主に非同期 Executor が有効な場合にのみ顕在化し、従来の同期モードのテストでは検出されませんでした。そのため、テスト結果の信頼性を損なうリスクが指摘されていました。

技術的な変更

check_connection_leaks メソッド内部で、reaper_lock の保護下に wait_for_pool_maintenance を呼び出すコードが追加されました。これにより、ロック取得後にプールのメンテナンスが完全に完了するまで待機した上で、従来通り pool.reap と接続の検査が行われます。

@@ -62,6 +62,8 @@ def check_connection_leaks
         pool.reaper_lock do
+          wait_for_pool_maintenance(pool)
           pool.reap
           pool.connections.each do |conn|

新たに導入された `wait_for_pool_maintenance` メソッドは、5 秒のデッドラインまでポーリングを行い、`@maintaining` が 0 かつ非同期 Executor の `completed_task_count` が `scheduled_task_count` と一致することを確認します。条件が満たされるかタイムアウトになるまで 0.05 秒間隔でスリープしながら待機します。

```ruby:activerecord/test/cases/test_case.rb
@@
   def wait_for_pool_maintenance(pool)
     deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + 5

     while Process.clock_gettime(Process::CLOCK_MONOTONIC) < deadline
       pool.synchronize do
         executor = pool.async_executor

         return if pool.instance_variable_get(:@maintaining).zero? &&
           executor&.completed_task_count == executor&.scheduled_task_count
       end

       sleep 0.05
     end
   end

同時に、`activerecord/test/cases/test_case_test.rb` には新しいテストケースが追加され、非同期リエーパーが実行中でも `check_connection_leaks` が正しく動作することが検証されています。テストはフェイク Executor と `Concurrent::Event` を用いて、メンテナンス中の接続が一時的に使用中であることをシミュレートし、待機ロジックが期待通りに機能することを確認します。

## 設計判断

今回の改修は、既存の **`check_connection_leaks`** のシグネチャや呼び出し側ロジックを変更せず、内部で待機処理を挿入する形で実装されました。これにより、従来の同期モードの動作に影響を与えず、非同期 Executor が設定されていない環境でも同一コードがそのまま動作します。新メソッドはプライベートヘルパーとして実装され、テストコードからスタブ化可能な設計となっています。

また、デッドラインとポーリング間隔を固定値で設定することで実装をシンプルに保ち、過度なパラメータ化を避けています。テストは新旧両方のシナリオを網羅し、リグレッションのリスクを低減する方針が取られました。

## まとめ

`check_connection_leaks` に非同期リエーパーの完了待機を組み込んだことで、非同期 Executor 環境でも接続リークの誤検知が防止されました。既存コードへの侵入を最小限に抑えつつ、テストカバレッジを拡充した設計判断が特徴です。

記事メタデータ

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

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

リード文・背景・技術的変更・設計判断・まとめの5部構成が明確で、総論→各論→結論の流れが保たれています。

カスタムMarkdown構文 ✓ PASS

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

ファイル名付きシンタックスハイライトは正しい形式 (```ruby:filepath) で使用され、PRリンクは [#57744](URL) 形式です。

対象読者への適合性 ✓ PASS

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

専門的なRails内部実装の説明が中心で、初心者向けの過度な解説はなく、対象読者に適合しています。

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

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

各セクションは総論→各論→結論の段落構成で、トピックセンテンスが先頭にあり、1段落1トピック・長さも適切です。空行で区切られています。

Diff内容との照合 ✓ PASS

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

記事中のコードブロックはDiffと完全に一致しており、追加された wait_for_pool_maintenance の実装と呼び出し箇所が正確に反映されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

async executor、reaper_lock、wait_for_pool_maintenance などの用語はPRで使用されている通り正しく記述されています。

説明の技術的正確性 ✓ PASS

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

5秒のデッドラインや0.05秒間隔のポーリングといった技術的詳細はDiffと整合し、説明に誤りはありません。

事実の突合 ✓ PASS

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

全ての主張がPRのタイトル、説明、Diffおよびテスト追加に裏付けられており、ハルシネーションは見られません。

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

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

5 秒、0.05 秒、PR番号 #57744 などの数値・固有名詞は正確です。

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

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

記事タイトルはPRタイトルの意味を正しく日本語化しており、内容と一致しています。

外部知識の正確性 ✓ PASS

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

LTSやリリース日程等、PRに無関係な外部知識は記載されていません。

時間表現の正確性 ✓ PASS

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

時間表現は5秒のデッドラインのみで、PRの記述と矛盾はありません。