Evented LogSubscriber を Ractor 安全な共有可能に変更

rails/rails

EventReporter の内部で使用されている LogSubscriber がプロックを保持したままでは Ractor 間で安全に共有できません。本 PR はそのプロック保持を排除し、動作を変えずに Ractor 安全な実装へとリファクタリングします。

背景

LogSubscriberLEVEL_CHECKS というハッシュに debug, info, error 各レベル用のプロックを格納していました。これらのプロックは ActiveSupport::Ractors.shareable_lambda で共有可能にしていたものの、プロック自体が Ractor の境界を越える際に重いオーバーヘッドと可読性の低下を招いていました。Ractor 安全性を確保するためには、定数にプロックを残さずシンプルなデータだけを保持する設計が求められます。本変更はその要件を満たすことを目的としています。

技術的な変更

LogSubscriber の定数置き換え

変更前LEVEL_CHECKS ハッシュに ActiveSupport::Ractors.shareable_lambda でラップしたプロックが格納されていました。

-LEVEL_CHECKS = {
-  debug: ActiveSupport::Ractors.shareable_lambda(&-> (logger) { logger.debug? }),
-  info:  ActiveSupport::Ractors.shareable_lambda(&-> (logger) { logger.info? }),
-  error: ActiveSupport::Ractors.shareable_lambda(&-> (logger) { logger.error? })
-}.freeze
+LOG_LEVELS = [:debug, :info, :error].freeze

変更後 はレベル名だけを配列 LOG_LEVELS として保持し、実際の判定は log_level_satisfied? メソッドで行います。これにより定数は純粋なデータ構造のみとなり、Ractor 間で安全に共有できます。

emit メソッドの判定ロジック更新

emit での呼び出しは従来 LEVEL_CHECKS[log_levels[event_method]]&.call(logger) で行われていましたが、以下のように簡潔に置き換えられました。

-public_send(event_method, event) if LEVEL_CHECKS[log_levels[event_method]]&.call(logger)
+public_send(event_method, event) if log_level_satisfied?(event_method)

ログレベル判定ヘルパーの追加

新たに log_level_satisfied?(event_method) を実装し、現在のロガーが対象レベルを許容しているかを直接問い合わせます。

+def log_level_satisfied?(event_method)
+  event_log_level = log_levels[event_method]
+  return false unless LOG_LEVELS.include?(event_log_level)
+  logger.public_send("#{event_log_level}?")
+end

この実装は LOG_LEVELS に含まれないレベルが指定された場合は常に false を返すことで安全性を確保します。

StructuredEventSubscriber のデバッグチェック簡素化

StructuredEventSubscriber でも同様にプロックを排除し、DEBUG_CHECK 定数を削除して silenced_events のハッシュ値を true に置き換えました。

@@ -31,8 +31,6 @@
-    DEBUG_CHECK = ActiveSupport::Ractors.shareable_proc { !ActiveSupport.event_reporter.debug_mode? }
@@
-            subscriber.silenced_events = debug_methods.to_h { |method| ["#{method}.#{namespace}", DEBUG_CHECK] }
+            subscriber.silenced_events = debug_methods.to_h { |method| ["#{method}.#{namespace}", true] }
@@
-      ActiveSupport.event_reporter.subscribers.none? || @silenced_events[event]&.call
+      ActiveSupport.event_reporter.subscribers.none? || (@silenced_events.key?(event) && !ActiveSupport.event_reporter.debug_mode?)

silenced? のロジックもプロック呼び出しを排除し、debug_mode? の反転チェックに変更しました。これにより同様に Ractor 安全な構造となります。

設計判断

本リファクタリングは プロックを定数に保持しない という方針で実装されています。shareable_lambdashareable_proc を使用すると可読性が低下し、Ractor 境界でのコピーコストが増大しますが、配列と直接的なロガーメソッド呼び出しに置き換えることで、コードベースのシンプルさとパフォーマンスの両立が可能になりました。変更範囲は限定的で、既存の log_levels ハッシュや外部インタフェースはそのまま保持されるため、下位互換性も維持されています。

まとめ

この PR は Evented LogSubscriber と StructuredEventSubscriber からプロック定数を除去し、シンプルなデータ構造と直接的なロガーレベル判定へと置き換えることで、Ractor 安全かつ可読性の高い実装に改めました。動作は従来と変わらず、Ractor を活用したマルチスレッド環境でも安全に利用できるようになります。

記事メタデータ

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

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

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

カスタムMarkdown構文 ⚠ WARNING

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

ファイル名付きシンタックスハイライトは正しい形式です。PRリンクは `[PR #57946](URL)` と記載されており、`[ #123 ](URL)` の厳密な形式ではありませんが可読性には問題ありません。

対象読者への適合性 ✓ PASS

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

エンジニアを対象とした専門的な記述で、初心者向けの余計な説明はありません。

パラグラフ・ライティング ⚠ WARNING

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

ほとんどの段落はトピックセンテンスで始まり、1段落1トピックで適切な長さです。ただし、背景セクションに結論的なまとめ段落がなく、総論・各論・結論の完全な構造が若干欠けています。

Diff内容との照合 ✓ PASS

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

記事内のコードブロックは提供されたDiffと完全に一致しており、変更箇所・追加箇所が正確に反映されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「Ractor 安全」「shareable_lambda」「shareable_proc」などの用語はPRで使用されているものと一致し、誤用はありません。

説明の技術的正確性 ✓ PASS

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

技術的主張はPRのMotivationとDiffで裏付けられており、誤った説明はありません。

事実の突合 ✓ PASS

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

全ての事実はPR情報とDiffに基づいており、外部知識や根拠のない推測は含まれていません。

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

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

PR番号 #57946 などの固有名詞は正しく記載されています。

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

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

記事タイトルはPRの趣旨「Evented LogSubscriber を shareable にする」ことを日本語で適切に表現しています。

外部知識の正確性 ✓ PASS

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

記事内にPRに記載されていない外部知識(LTS、リリース日程等)は含まれていません。

時間表現の正確性 ✓ PASS

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

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