Redis再接続時に保留中のサブスクライブ確認を保持する修正

rails/rails

Redis の Pub/Sub 接続が切断された際に、ActionCable::SubscriptionAdapter::Redis::Listener が保持していたサブスクライブ成功コールバックが破棄されていた問題を解消します。reset メソッドから @subscribe_callbacks.clear を除去し、再接続後でも未完了の確認が配信されるようにしました。

背景

Listener#reset が呼び出されると @subscribe_callbacks がクリアされ、接続ドロップ直前に送信済みだが応答待ちのサブスクライブ確認が失われていました。その結果、再接続後に SUBSCRIBE が再送されてもコールバックが存在せず、クライアント側で confirm_subscription が決して解決せずにスタックしたままになります。これは Redis クライアントの書き換え(コミット ef812c2652)に伴う回帰であり、同時期にマージされた PR #57690 が対象としているリスナースレッドの終了バグとは別の箇所です。失われたコールバックが原因で、実際にはチャンネルは正常に購読できているにもかかわらず、アプリケーション側で永続的にサブスクライブ待ち状態になるケースが報告されました。

技術的な変更

reset メソッドから @subscribe_callbacks.clear 行が削除されました。変更前後を示すと次のようになります。

@@
   def reset
     @subscription_lock.synchronize do
       @subscribed_client = nil
-      @subscribe_callbacks.clear
       @when_connected.clear
     end
   end

この修正により、リセット時に残っているコールバックは保持され、再接続後の resubscribe が送出する SUBSCRIBE の ACK で正しく呼び出されます。既に確認済みのチャンネルはコールバック実行後に自身のエントリを削除するため、古いコールバックが残ることはありません。結果として、再接続シナリオでもサブスクライブフローが中断せずに完了します。

設計判断

@subscribe_callbacks をクリアしない方針は、正しい再接続時の動作を保証することを最優先した選択です。完全にアンサブスクライブされたチャンネルが接続ドロップの間に残っていた場合、コールバックがリークする可能性がありますが、対象チャンネルは @subscribers から除外されているため再サブスクライブの対象にもならず、影響は極めて限定的です。将来的にリーク対策を追加する余地は残しつつ、現在は既存ロジックを大幅に改変せずにバグを解消するというトレードオフが採られました。

まとめ

reset から @subscribe_callbacks.clear を除去したことで、Redis 接続の再接続時に保留中のサブスクライブ確認が失われず、クライアントは正しく confirm_subscription を受け取れるようになりました。テストも追加され、実際のリスナーループをフェイク接続で制御し、競合状態でも期待通りに確認が配信されることが検証されています。

記事メタデータ

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

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

リード文(総論)→背景(Context)→技術的変更(Technical Detail)→設計判断(Design Insight)→まとめ(結論)の流れが明確で、全要素が揃っている。

カスタムMarkdown構文 ✓ PASS

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

コードブロックは `ruby:actioncable/lib/action_cable/subscription_adapter/redis.rb` という正しいファイル名付きハイライト形式。PRリンクは `[PR #57695](URL)` の形で正しく記述されている。

対象読者への適合性 ✓ PASS

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

Rails/ActionCable の内部実装に関する専門的な記述で、エンジニア向けに適切なレベル。初心者向けの過剰な説明はない。

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

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

各セクションは総論・各論・結論の構成を保持し、段落はトピックセンテンスで始まり1段落1トピック。文数は6文以下で適切に区切られている。

Diff内容との照合 ✓ PASS

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

記事中のコードブロックは提供された Diff と完全に一致し、削除された `@subscribe_callbacks.clear` 行が正しく示されている。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

用語(Listener、reset、@subscribe_callbacks、ACK など)は PR と一致し、誤用は見られない。

説明の技術的正確性 ✓ PASS

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

技術的説明は PR の問題点・修正内容・テスト方針と合致しており、論理的に正しい。

事実の突合 ✓ PASS

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

すべての主張は PR のタイトル、説明、Diff に裏付けられており、外部情報や推測は含まれていない。

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

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

PR 番号 #57695、コミット ID ef812c2652 などの数値・固有名詞は正確。

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

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

記事タイトルは PR の内容「保留中のサブスクライブ確認を保持する」ことを適切に要約している。

外部知識の正確性 ✓ PASS

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

記事は PR に記載された情報以外の外部知識(バージョンサポート等)を付加していない。

時間表現の正確性 ✓ PASS

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

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