InheritableOptions を Ractor セーフにするための凍結ロジック変更

rails/rails

InheritableOptions が Ractor 環境で安全に共有できるよう、freeze 時のデフォルトプロック削除とキー追跡ロジックを導入しました。これにより、継承ハッシュの参照が原因で生じていた共有不可問題が解消されます。

背景

Ractor はオブジェクトの共有を明示的に許可しなければならないため、InheritableOptions が内部で保持している default_proc が参照している親ハッシュが共有不可になると、オブジェクト全体を Ractor で安全に扱えませんでした。現在の実装では default_proc がキー不在時に親ハッシュを参照するため、プロック自体が親オブジェクトへの参照を持ち、Ractor.make_shareable が適用できませんでした。そこで、プロックと親オブジェクトの相互依存を解消しつつ、継承機能を維持する手段が求められました。

技術的な変更

activesupport/lib/active_support/ordered_options.rbfreeze メソッドが新たに実装され、凍結時にデフォルトプロックを除去し、親ハッシュを凍結した上で自身のハッシュをマージします。これにより、default_proc が不要になり、オブジェクト全体が shareable になる前提が整います。

def freeze
  return self if frozen?

  @own_keys = own_keys.dup.freeze
  self.default_proc = nil
  @parent.freeze
  replace(to_h)
  super
end

キー集合の取得ロジックも改良され、keys が親ハッシュと自身のキーの和集合を返すようになりました。内部的に元々の own_key? をプライベートメソッド _own_keys にリネームし、own_keys は凍結前に保存した @own_keys か、元のキー集合を返すように統一しました。

alias_method :_own_keys, :keys
private :_own_keys

def keys
  @parent.keys | super
end

private
  def own_key?(key)
    own_keys.include?(key.to_sym)
  end

  def own_keys
    @own_keys || _own_keys
  end

overridden? メソッドはそのまま残しつつ、own_key? の実装が新しいキー追跡に依存するようになり、凍結後でも正しくオーバーライド判定が行えるようになりました。

テストコード activesupport/test/ordered_options_test.rb では、ActiveSupport::Testing::RactorsAssertions を取り入れ、assert_ractor_make_shareable による Ractor 共有可能性の検証が追加されました。また、keys の順序保証と凍結後の overridden? 動作をそれぞれ確認するテストが新設されています。

require "active_support/testing/ractors_assertions"

class OrderedOptionsTest < ActiveSupport::TestCase
  include ActiveSupport::Testing::RactorsAssertions

  def test_inheritable_options_ractor_shareable
    object = ActiveSupport::InheritableOptions.new(one: "first value")
    object[:two] = "second value"
    object["three"] = "third value"

    assert_ractor_make_shareable(object)
  end

  def test_overridden_works_when_frozen
    object = ActiveSupport::InheritableOptions.new(one: "first value", two: "second value")
    object[:two] = "second value"
    object["three"] = "third value"

    object.freeze
    assert object.overridden?(:two)
  end
end

設計判断

デフォルトプロックを凍結時に除去し、親ハッシュをマージして置換する という方針が採用されました。プロック自体を Ractor‑shareable に変換しようとすると、親オブジェクトの安全性を保証できないという制約があり、逆にプロックを残すとオブジェクト全体が共有不可になるため、機能的にも安全面でもトレードオフが明確です。

マージ後のハッシュは従来と同様にキー参照が可能ですが、遅延参照 が失われる点は設計上の妥協です。代わりに、凍結済みオブジェクトが即座に全鍵を持つ形になるため、参照コストは減少し、Ractor 環境での使用がシンプルになります。

キー追跡用に @own_keys を導入したことで、overridden? が凍結前後で一貫した結果を返すようになり、既存の API 互換性を保ちつつ新しい安全性を提供できます。この変更は最小限のコード追加で済み、既存の InheritableOptions の振る舞いに影響を与えません。

まとめ

freeze 時にデフォルトプロックを除去し、親ハッシュをマージしてキー集合を固定化することで、InheritableOptions が Ractor 環境でも安全に共有できるようになりました。追加されたキー追跡ロジックにより overridden? の正確さが保たれ、既存 API との互換性を維持しつつ新たなマルチスレッド安全性が提供されます。

記事メタデータ

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

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

リード文、背景、技術的変更、設計判断、まとめの全てが揃っており、総論→各論→結論の構成が明確です。

カスタムMarkdown構文 ⚠ WARNING

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

コードブロックのファイル名付きシンタックスハイライトは正しい形式です。PRリンクの表記が「[PR #57757](URL)」となっており、仕様の「[#123](URL)」と完全には一致していません。

対象読者への適合性 ✓ PASS

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

Railsエンジニア向けの高度な技術内容で、初心者向けの過度な説明はありません。

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

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

各セクションは総論・各論・結論の段落構成になっており、段落はトピックセンテンスで始まり、1段落1トピック、長さも適切です。空行で区切られています。

Diff内容との照合 ⚠ WARNING

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

freeze メソッドと keys ロジックのコードはDiffと一致していますが、テストファイルの追加された `test_inheritable_options_keys` など一部コードが記事に省略されています。省略は技術的理解に大きく支障しませんが、完全なDiff再現ではありません。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

PRで使用されている用語(freeze、default proc、shareable、Ractor、InheritableOptions、overridden?)が正確に使われています。

説明の技術的正確性 ✓ PASS

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

記事中の技術的主張はPRの内容と合致しており、因果関係も論理的です。

事実の突合 ✓ PASS

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

PR情報に基づかない数値や外部知識の記載はなく、事実に即した記述です。

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

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

PR番号 #57757 が正しく記載されており、その他数値・固有名詞の誤りはありません。

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

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

記事タイトルはPRの趣旨「Make InheritableOptions ractor safe」を日本語で適切に表現しています。

外部知識の正確性 ✓ PASS

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

LTSやリリース日程といった外部知識は含まれていません。

時間表現の正確性 ✓ PASS

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

時間表現の歪曲はありません。