ActionCableの再起動時にハートビートタイマーを停止

rails/rails

開発環境でコードがリロードされるたびに ActionCable::Server::Base#restart がハートビート用の Concurrent::TimerTask を停止せず、余分なスレッドプールが生成されていました。この PR はそのタイマーを他のリソースと同様に確実に終了させ、リソースリークを防ぎます。

背景

ActionCable のサーバーは restart 時に @worker_pool@executor@pubsub を停止し nil に設定しますが、heartbeat timer (@heartbeat_timer) の停止処理が抜けていました。タイマーは BEAT_INTERVAL 毎にブロックを実行し、その中で executor を遅延的に取得するため、restart 後に新たな executor スレッドプールが再生成されます。結果として、開発モードのコードリロードごとにスレッドプールがリークし、サーバーが停止したはずなのにハートビートが残り続けます。

この問題は開発時のパフォーマンス低下だけでなく、長時間稼働させた際に不要なスレッドが蓄積しメモリ使用量が増大する原因となります。

技術的な変更

initialize メソッドで @heartbeat_timernil に初期化する行が追加され、他の遅延生成リソースと同様の初期状態が確立されました。

@@
-        @remote_connections = @event_loop = @worker_pool = @executor = @pubsub = nil
+        @remote_connections = @event_loop = @worker_pool = @executor = @pubsub = @heartbeat_timer = nil

restart 内に以下のコードが挿入され、タイマーが存在すれば shutdown を呼び出し、続いて nil にクリアします。これにより、setup_heartbeat_timer が次回リクエスト時に再度タイマーを作成するまで、リソースは完全に解放されます。

@@
-          # Shutdown the worker pool
-          @worker_pool.halt if @worker_pool
-          @worker_pool = nil
+          # Shutdown the heartbeat timer
+          @heartbeat_timer.shutdown if @heartbeat_timer
+          @heartbeat_timer = nil
+
+          # Shutdown the worker pool
+          @worker_pool.halt if @worker_pool
+          @worker_pool = nil

テスト BaseTest#restart shuts down the heartbeat timer が追加され、タイマーが restart 後に running? が偽になることと、インスタンス変数が nil になることを検証しています。4 回のリロードシナリオで緑(成功)が確認されています。

@@
-  end
+  end
+
+  test "#restart shuts down the heartbeat timer" do
+    @server.send(:setup_heartbeat_timer)
+    timer = @server.instance_variable_get(:@heartbeat_timer)
+    assert_predicate timer, :running?
+
+    @server.restart
+
+    assert_not timer.running?
+    assert_nil @server.instance_variable_get(:@heartbeat_timer)
+  end
 end

設計判断

@heartbeat_timer を他の遅延作成リソースと同様に shutdownnil でクリアするパターンを採用し、リソース管理の一貫性を保ちました。

この変更は新しい設定キーを導入せず、既存の restart フローに最小限のコード追加で実装されているため、後方互換性への影響はありません。

バグ修正であるため CHANGELOG への記載は省かれていますが、開発環境でのメモリとスレッドの不要な増加を防ぐ重要な改善です。

まとめ

今回の修正により、ActionCable の再起動時に残っていたハートビートタイマーが適切に停止・破棄され、開発コードリロード時のスレッドプールリークが解消されました。リソース管理の統一とリーク防止という観点で、安定した開発体験が提供されます。

記事メタデータ

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

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

リード文→背景・技術的な変更・設計判断・まとめの3部構成が明確に示されており、総論・各論・結論が揃っている。

カスタムMarkdown構文 ⚠ WARNING

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

コードブロックのファイル名付きハイライトは正しい形式(````ruby:filepath`)。GitHubリンクは[PR #57700](URL)となっており、#のみの形式([#57700](URL))ではないため軽微な違反と判断した。

対象読者への適合性 ✓ PASS

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

エンジニア向けの技術的内容で、初心者向けの余計な解説はなく適切。

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

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

各セクションは総論パラグラフ・各論・結論パラグラフで構成され、段落はトピックセンテンスで始まり1段落1トピック、長さも適切。空行で区切られている。

Diff内容との照合 ✓ PASS

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

記事中のコードブロックは提供されたDiffと完全に一致しており、ファイル名・変更箇所とも合致している。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

ActionCable, restart, @heartbeat_timer, Concurrent::TimerTask などの用語はPRと整合して正しく使用されている。

説明の技術的正確性 ✓ PASS

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

リソースリークの原因や修正内容の説明がPRの記述と矛盾せず、技術的に正確。

事実の突合 ✓ PASS

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

すべての主張がPRのタイトル・説明・Diffで裏付けられており、捏造や推測は見られない。

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

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

PR番号やテスト回数(4回)などの数値は正確に記載されている。

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

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

記事タイトルはPRタイトル「Shut down the heartbeat timer on server restart」の意味を正しく日本語化している。

外部知識の正確性 ✓ PASS

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

バージョンサポートやリリース情報など、PRに含まれない外部知識は記載されていない。

時間表現の正確性 ✓ PASS

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

時間表現に関してPRと食い違う記述はなく、正確。