Ractor安全化のためのプロック共有機構を導入

rails/rails

Rails が Ractor 対応を進める中で、アプリケーションが提供する Proc が Ractor 共有可能であるかどうかを判定し、必要に応じて安全化する仕組みが追加されました。これにより、非共有プロックが原因で発生する Ractor::IsolationError を事前に検知し、適切に対処できるようになります。

背景

Rails アプリケーションが Ractor セーフであることは、マルチスレッド実行環境での安定運用に不可欠です。しかし、Rails.application.routes.draw などの API に Proc を渡すケースでは、内部でその Proc が共有されず Ractor::IsolationError が発生することがあります(例: resolve("Cart") { to_resolve })。この問題はエラーメッセージが遅延して現れるため、デバッグが困難です。

本 PR は、プロックの共有可否を明示的にチェックし、三つのモードで振る舞いを選択できる仕組みを提供します。デフォルトはオプトインで無効化されており、既存アプリへの影響を最小限に抑えつつ、将来的に安全化機能を段階的に導入できる設計となっています。

技術的な変更

ActiveSupport::Ractors に新たにアクセサ unshareable_proc_action とヘルパーメソッド try_shareable_proc が追加されました。このメソッドは渡された Proc を Ractor.make_shareable で共有化しようと試み、Ractor::IsolationError が発生した場合に :raise:warnnil の設定に応じて例外を再送出、デプリケーション警告を出す、何もしないのいずれかの動作を取ります。

module ActiveSupport
  module Ractors
    class << self
      attr_accessor :unshareable_proc_action

      def try_shareable_proc(proc = nil, &block)
        proc ||= block
        return proc unless unshareable_proc_action

        shareable_proc(&proc)
      rescue Ractor::IsolationError
        case unshareable_proc_action
        when :raise
          raise
        when :warn
          ActiveSupport.deprecator.warn(<<~MSG)
            Rails attempted to make a Proc from your application Ractor shareable but a Ractor
            Isolation error was raised. The proc being returned is not Ractor safe and a runtime
            error may occur anytime during the request lifecycle.

            #{proc.inspect}
          MSG
          proc
        end
      end

ActionDispatch::Routing::RouteSet の URL ヘルパー生成ロジックが修正され、ActiveSupport::Ractors.try_shareable_proc がプロック取得時に呼び出されるようになりました。これにより、ルートヘルパー定義時点でプロックの安全性が検証されます。

class CustomUrlHelper
  def initialize(name, defaults, &block)
    @name = name
    @defaults = defaults
-    @block = block
+    @block = ActiveSupport::Ractors.try_shareable_proc(block)
  end

テストスイートが拡充され、unshareable_proc_action の三モードすべてに対する期待動作が検証されていますRouteSetTest では resolve メソッドに非共有プロックを渡した際の例外、警告、無視の挙動が確認され、RactorsTest では try_shareable_proc の内部ロジックが単体テストで網羅されています。

設計判断

本機構はオプトイン方式で実装され、デフォルトは無効 (nil) です。これにより、既存アプリケーションが即座に破壊されるリスクを回避しつつ、開発者が意図的に安全化を有効化できるポイントを提供しています。unshareable_proc_action の設定はグローバルに行えるため、環境ごとに挙動を切り替えることが容易です。

例外を即座に通知する :raise と、デプリケーション警告で緩やかに導入する :warn の二択は、移行期間の柔軟性を確保する設計上のトレードオフを示しています:raise は開発・テスト環境での早期検出に適し、:warn は本番環境での互換性維持と段階的リファクタリングを支援します。いずれのモードでもコード変更は最小限に抑えられ、既存 API との互換性が保たれています。

記事メタデータ

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

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

品質レビュー結果

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

Review Criteria:

記事構成 ⚠ WARNING

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

リード文はあるが、明確な「まとめ」セクションが欠如している。設計判断が結論的要素を含んでいるものの、記事全体の結論として独立した段落がないため、WARNING とした。

カスタムMarkdown構文 ✓ PASS

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

コードブロックは `言語:ファイルパス` 形式で正しく記述され、PRリンクも `[#123](URL)` 形式で正しくリンク化されている。

対象読者への適合性 ✓ PASS

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

対象は Rails エンジニアで、専門用語や内部実装に焦点を当てており、初心者向け過度な説明はない。

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

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

各セクションは総論・各論・結論の構成を概ね保ち、段落はトピックセンテンスで始まり 1トピック・適切な長さで記述されている。段落間も空行で区切られている。

Diff内容との照合 ✓ PASS

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

記事中のコードブロックは Diff の変更点と一致しており、ファイル名・内容ともに正確に反映されている。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

Proc、Ractor、IsolationError などの用語は PR 内容と一致し、誤用は見られない。

説明の技術的正確性 ✓ PASS

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

技術的説明は PR の背景・詳細と整合性が取れており、機能や挙動の記述に誤りはない。

事実の突合 ✓ PASS

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

記事の主張はすべて PR の記載内容、Diff、テストコードに裏付けられており、推測や根拠のない情報は含まれていない。

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

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

PR 番号 #57626 が正しく記載されており、他の数値・固有名詞の誤りはない。

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

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

日本語タイトルは PR の意図(Ractor 安全化機構の導入)を適切に要約している。

外部知識の正確性 ✓ PASS

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

LTS、EOL、リリース日程等の外部知識は記事に含まれておらず、PR に基づく記述に限定されている。

時間表現の正確性 ✓ PASS

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

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