Action Cableのアダプタでeager loadingをRedisとPostgreSQLのみに限定
Action Cableは、Redis と PostgreSQL のサブスクリプションアダプタだけを eager loading から除外し、他の軽量アダプタは従来どおり eager load されるように変更しました。これにより起動時のロードコストを抑えつつ、特定アダプタに依存するオプションの遅延ロードを維持します。
背景
Action Cable は loader.do_not_eager_load にサブスクリプションアダプタのディレクトリ全体を指定し、オプション依存を持つアダプタを遅延ロードしていました。この方針は、Redis アダプタが Base と ChannelPrefix をファイルロード時に参照するため、Zeitwerk のラジウム競合で NameError が発生する問題を引き起こしました(PR #57249 では明示的 require を追加して回避)。しかし、Redis と PostgreSQL 以外のアダプタはコードサイズが小さいため、eager loading をスキップしても得られるメリットが限定的でした。結果として、過度な除外が不要な複雑さをもたらすことが判明しました。
この背景から、ディレクトリ単位の除外から、影響の大きい Redis と PostgreSQL のファイルのみを対象に限定する方針が採用されました。
技術的な変更
actioncable/lib/action_cable.rb の do_not_eager_load の対象変更
loader.do_not_eager_load が受け取るパスをディレクトリから個別ファイルへ変更し、コメントで意図を明示しました。
@@ -41,7 +41,10 @@
)
loader.do_not_eager_load(
- "#{lib}/action_cable/subscription_adapter", # Adapters are required and loaded on demand.
+ # These adapters trigger optional dependencies so they are required and loaded on demand.
+ "#{lib}/action_cable/subscription_adapter/redis.rb",
+ "#{lib}/action_cable/subscription_adapter/postgresql.rb",
"#{lib}/action_cable/test_helper.rb",
Dir["#{lib}/action_cable/**/test_case.rb"]
)
この変更により、Redis と PostgreSQL の adapter だけが eager loading から除外され、他の async.rb、inline.rb、test.rb などは標準的に eager load の対象となります。
actioncable/lib/action_cable/subscription_adapter/redis.rb の不要な require の削除
Redis アダプタから、Base と ChannelPrefix の明示的 require が削除されました。ファイルは依然として Base を継承しますが、do_not_eager_load に列挙されているため、実行時に初めてロードされ、Zeitwerk が自動的に依存クラスを解決します。
@@ -7,9 +7,6 @@
require "active_support/core_ext/hash/except"
-
-require "action_cable/subscription_adapter/base"
-require "action_cable/subscription_adapter/channel_prefix"
-
module ActionCable
module SubscriptionAdapter
class Redis < Base # :nodoc:
この削除は、アダプタ自身が依存をロードするという既存のスタイル(require がなくても Zeitwerk が適切に処理)に合わせたものです。
変更の影響
- Redis と PostgreSQL 以外のアダプタは起動時に eager load され、ロード回数が減少し、
NameErrorのレースコンディションリスクが低減します。 - 既存の
config.action_cable.subscription_adapter = :redis等の設定は動作に影響しません。削除されたrequireは不要なオーバーヘッドだけだったため、互換性は保たれます。
設計判断
スコープ限定の除外という選択は、起動時間の最適化と コードベースの一貫性 のトレードオフを再評価した結果です。ディレクトリ全体を除外すると、軽量な adapter まで遅延ロードされ、不要な遅延が発生します。一方で Redis と PostgreSQL はオプション依存(外部サービスクライアント)を持つため、起動時に必ずしもロードすべきでないという設計方針が残ります。
また、redis.rb から require 行を削除した点は、「アダプタは自らの依存を明示的に require しない」という既存スタイルを尊重したものです。これにより、コード量が減り、コメントと実装の乖離がなくなります。
総合的に、必要最小限の除外対象に絞ることで、パフォーマンス向上と保守性向上の両立を図った設計判断と言えます。
まとめ
この PR は Action Cable のサブスクリプションアダプタに対し、Redis と PostgreSQL のみを eager loading から除外し、他の軽量アダプタは標準的に eager load させることで、起動時のロードコストを削減しつつ、既存の遅延ロード方針を維持しました。不要になった require の削除はコードベースの一貫性を保ち、今後のアダプタ追加時の指針にもなります。