Action Cable Redis アダプタを redis-client で再実装
Action Cable の Redis アダプタが従来の redis gem から軽量な redis-client に置き換えられ、依存サイズの削減と API の単純化が実現されました。これにより、機能的な振る舞いは維持しつつ、ランタイムのフットプリントが小さくなります。
背景
従来の Action Cable Redis アダプタは redis gem (>= 4, < 6) に強く依存しており、gem 自体が数百キロバイトに及ぶ大きさでした。PR #57004 でキャッシュストアが redis-client に置き換えられたことを受け、同様の軽量化を Action Cable にも適用する狙いがありました。redis-client は RESP2 プロトコルをデフォルトで使用し、サーバ側の要件変更は不要です。これにより、Rails アプリケーション全体の依存関係がシンプルになることが期待されました。
技術的な変更
依存ライブラリの差し替え として、actioncable/lib/action_cable/subscription_adapter/redis.rb の冒頭で gem "redis" を gem "redis-client" に、require "redis" を require "redis-client" に変更しました。
-gem "redis", ">= 4", "< 6"
-require "redis"
+gem "redis-client"
+require "redis-client"
接続生成ロジックの刷新 では、redis_connector が RedisClient.config または RedisClient.sentinel を呼び出し、返されたオブジェクトからプールを生成するようになりました。config から :adapter と :channel_prefix を除外し、id が未指定ならデフォルトで ActionCable-PID-#{$$} を設定します。
- ::Redis.new(config.except(:adapter, :channel_prefix))
+ config = config.except(:adapter, :channel_prefix)
+ config[:id] ||= "ActionCable-PID-#{$$}"
+
+ redis_config = if config.key?(:sentinels)
+ ::RedisClient.sentinel(**config)
+ else
+ ::RedisClient.config(**config)
+ end
+ redis_config.new_pool
ブロードキャストの実装変更 では、従来の publish メソッド呼び出しを call("publish", ...) に置き換え、redis-client の汎用呼び出しインターフェースに合わせました。
- redis_connection_for_broadcasts.publish(channel, payload)
+ redis_connection_for_broadcasts.call("publish", channel, payload)
サブスクライブ側の処理 では、listen メソッドが conn.pubsub から取得した pubsub_client を使用し、subscribe ループや再接続ロジックを redis-client の API に合わせてリファクタリングされています。変更前後の大きなロジックは削除され、シンプルな pubsub_client.subscribe 呼び出しに集約されました。
テストコードの更新 も同様に RedisClient.config を用いたインスタンス生成に合わせ、call 系メソッドへ置き換えられました。これにより、テストは実装変更を正確に反映しています。
- @redis_conn ||= ::Redis.new(cable_config.except(:adapter))
+ @redis_conn ||= ::RedisClient.config(**cable_config.except(:adapter)).new_client
@@
- redis_conn.client("kill", "type", "pubsub")
+ redis_conn.call("client", "kill", "type", "pubsub")
@@
- break if redis_conn.pubsub("numsub", channel).last > 0
+ break if redis_conn.call("pubsub", "numsub", channel).last > 0
設計判断
既存の設定キーを残す方針 が採用され、redis: という構成オプションは引き続きサポートされています。redis-client に切り替えることで API が変化しましたが、外部からの呼び出しシグネチャは可能な限り同一に保たれ、後方互換性が確保されています。
依存削減とシンプル化 を最優先にした設計選択は、redis-client が提供する軽量なコネクションプーリングとシンプルなコマンド呼び出しインターフェースに基づいています。結果として、Action Cable の Redis アダプタは機能的に等価でありながら、バンドルサイズが小さくなり、アプリケーション全体の依存ツリーが簡潔になります。
まとめ
本 PR は Action Cable の Redis アダプタを redis-client に置き換えることで、redis gem への大きな依存を排除し、API をシンプル化しました。変更は内部実装に留まり、既存の動作や設定オプションは維持されるため、利用者はコードや設定を変更せずに利益を享受できます。