ActiveSupport JSON エンコーダーの Ractor 共有化実装をリバート
Rails 8.1 で導入された Ractor‑shareable な JSON エンコーダーの実装を取り消し、従来の挙動に戻します。このリバートにより、Ractor 起動時に発生していた CI のフレーク問題が回避されます。
背景
前回の PR(#57814)では、ActiveSupport::JSON のエンコーダーを Ractor から安全に呼び出せるよう Ractor‑shareable 化する変更が加えられましたが、テスト実行順序に依存して "[BUG] should have cvar cache entry" というクラッシュが sporadically 発生しました。PR の説明でも "CI flakiness" と明記されており、安定運用の阻害要因となったため、元の実装に戻す判断が下されました。
技術的な変更
Gemfile.lock のバージョンダウングレード
- json (2.19.9)
+ json (2.15.2)
json gem のバージョンを 2.19.9 から 2.15.2 に戻すことで、Ractor‑shareable 用に追加された内部 API への依存を排除しました。
activesupport/lib/active_support/json/encoding.rb のロジック復元
- 定数の freeze 削除 と 正規表現の .freeze 除去 により、以前のシンプルなリテラル定義に戻しています。
-
JSONGemEncoderのコンストラクタでオプションをoptions.dup.freeze || {}.freezeからoptions || {}へ変更し、オプションハンドリングを元の形に復元しました。 -
JSONGemCoderEncoderのCODER生成がActiveSupport::Ractors.shareable_procラッパーから外れ、単純なブロック定義に戻されています。
@@ -61,22 +61,22 @@ module Encoding # :nodoc:
- U2028 => -'\u2028'.b,
- U2029 => -'\u2029'.b,
- ">".b => -'\u003e'.b,
- "<".b => -'\u003c'.b,
- "&".b => -'\u0026'.b,
+ U2028 => '\u2028'.b,
+ U2029 => '\u2029'.b,
+ ">".b => '\u003e'.b,
+ "<".b => '\u003c'.b,
+ "&".b => '\u0026'.b,
@@ -65,9 +65,9 @@
- HTML_ENTITIES_REGEX = Regexp.union(*(ESCAPED_CHARS.keys - [U2028, U2029])).freeze
- FULL_ESCAPE_REGEX = Regexp.union(*ESCAPED_CHARS.keys).freeze
- JS_SEPARATORS_REGEX = Regexp.union(U2028, U2029).freeze
+ HTML_ENTITIES_REGEX = Regexp.union(*(ESCAPED_CHARS.keys - [U2028, U2029]))
+ FULL_ESCAPE_REGEX = Regexp.union(*ESCAPED_CHARS.keys)
+ JS_SEPARATORS_REGEX = Regexp.union(U2028, U2029)
@@ -144,7 +144,7 @@
- @options = options.dup.freeze || {}.freeze
+ @options = options || {}
@@ -149,7 +149,7 @@
- CODER = ::JSON::Coder.new(&ActiveSupport::Ractors.shareable_proc { |value, is_key|
+ CODER = ::JSON::Coder.new do |value, is_key|
@@ -177,7 +177,8 @@
- }).freeze
+ end
+
テスト削除
activesupport/test/json/encoding_test.rb から Ractor 共有化に関するテストブロックが削除され、Ruby 4.0 以上での条件分岐コードが除かれました。これにより、テストスイートは Ractor に依存しない状態に戻ります。
@@ -582,23 +582,6 @@
- if RUBY_VERSION >= "4.0"
- def test_encoders_are_ractor_shareable
- skip "Missing Ractor-shareable JSON::Coder" unless Gem::Version.new(::JSON::VERSION) >= Gem::Version.new("2.17.0")
- ...
- end
- end
-
設計判断
今回のリバートは 安定性優先 の設計判断を示しています。Ractor 共有化は将来的な機能として残す意図があり、4.0.6 のリリースを待った上で再度導入検討する方針です。その間は従来のシングルスレッド向け実装を維持し、既存のテストと CI の信頼性を確保することが選択されました。実装を元に戻すことで、後方互換性はそのまま保たれ、ユーザーコードへの影響はありません。
まとめ
この PR は、Ractor 環境での JSON エンコーディングを試みた変更を取り消し、CI の不安定化を防止するための 安定化リバート です。json gem のバージョンを 2.15.2 に固定し、エンコーダー内部の Ractor‑shareable ロジックとそれに伴うテストを削除することで、従来の堅牢な実装に戻しました。今後は Ruby 4.0.6 以降で改めて共有化機能を導入する予定です。