EventReporterのペイロード構築を購読者フィルタリング後に実行

rails/rails

ActiveSupport::EventReporter のイベント通知処理が最適化され、購読者の有無を確認してからペイロードを構築するようになりました。この変更により、イベント発行時の不要なオーバーヘッドが削減されます。

背景

#55900 でフレームワークのログ購読者が構造化イベントを消費するよう変更された際、イベントフィルタリングの仕組みも移植されました。しかし、この実装では購読者の有無にかかわらず常にペイロードを構築してからフィルタリングを行っていたため、購読者が存在しない場合でもコストが発生していました。

ActiveSupport::Notifications では、フィルタリングによってペイロード構築を回避できる設計になっていましたが、EventReporter ではこの最適化が機能していませんでした。イベントペイロードの構築は、特に複雑なオブジェクトを含む場合にコストが高くなります。

本PRは、フィルタリング機能を実用的なものにするため、処理順序を見直しています。

技術的な変更

activesupport/lib/active_support/event_reporter.rbnotify メソッドが書き換えられ、ペイロード構築前にイベント名のみでフィルタリングを行うようになりました。

変更前:

def notify(name_or_object, payload = nil, caller_depth: 1, **kwargs)
  name = resolve_name(name_or_object)
  payload = resolve_payload(name_or_object, payload, **kwargs)

  event = {
    name: name,
    payload: payload,
    # ...
  }

  @subscribers.each do |subscriber_entry|
    subscriber = subscriber_entry[:subscriber]
    filter = subscriber_entry[:filter]

    next if filter && !filter.call(event)  # フィルタリングはペイロード構築後

    subscriber.emit(event)
  end
end

変更後:

def notify(name_or_object, payload = nil, caller_depth: 1, **kwargs)
  name = resolve_name(name_or_object)
  event = { name: name }  # イベント名のみの軽量オブジェクト

  subscribers = @subscribers.filter_map do |subscriber_entry|
    subscriber = subscriber_entry[:subscriber]
    filter = subscriber_entry[:filter]

    if !filter || filter.call(event)  # イベント名のみでフィルタリング
      subscriber
    end
  end

  return if subscribers.empty?  # 購読者がいなければペイロード構築をスキップ

  payload = resolve_payload(name_or_object, payload, **kwargs)

  event = {
    name: name,
    payload: payload,
    # ...
  }

  subscribers.each do |subscriber|
    subscriber.emit(event)
  end
end

フィルタリングに使用される event オブジェクトは :name キーのみを含むようになり、ペイロード構築は購読者が存在する場合のみ実行されます。購読者が存在しない場合は早期リターンにより、resolve_payload の呼び出しとイベントオブジェクトの完全な構築が回避されます。

設計判断

フィルタ関数に渡す情報をイベント名のみに制限する という判断が下されました。

PR作成者は、ペイロードベースのフィルタリング機能(例: event[:payload].is_a?(AuditEvent))を削除することは技術的には破壊的変更と認めつつも、現状の実装では実質的なオーバーヘッド削減にならないため意味がないと判断しています。CHANGELOGにも「フィルタ中は :name キーのみが利用可能で、ペイロード全体は利用できない」と明記されています。

この制約により、フィルタリングは常に軽量な文字列比較で済むようになり、ActiveSupport::Notifications と同様の最適化パターンが実現します。ペイロード内容に基づくフィルタリングが必要な場合は、購読者側の emit メソッド内で判断することになります。

まとめ

本PRは、イベント通知の処理順序を「ペイロード構築→フィルタリング→配信」から「フィルタリング→ペイロード構築→配信」に変更することで、不要なペイロード構築コストを削減しています。フィルタリング機能の制約(イベント名のみ)は破壊的変更ですが、実用性のない機能を削除することで、ActiveSupport::Notifications と同等の効率性を実現しています。

記事メタデータ

Generated by:
Claude Sonnet 4.5 for DiffDaily

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

品質レビュー結果

Review Status:
リトライ後承認
Review Count:
2回 (改善を経て承認)
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

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

リード文(総論)→背景・技術変更・設計判断(各論)→まとめ(結論)の3部構成が明確に適用されています。特に、PRに記載のあった設計上のトレードオフを「設計判断」セクションとして独立させている点が優れています。

カスタムMarkdown構文 ✓ PASS

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

ファイル名付きシンタックスハイライト(```ruby:path/to/file.rb)およびPR番号へのリンク記法([#123](URL))が正しく使用されています。

対象読者への適合性 ✓ PASS

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

「ペイロード」「オーバーヘッド」「早期リターン」といった用語を前提知識として使用しており、専門知識を持つエンジニアという対象読者に適合した内容になっています。

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

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

各セクションが総論→各論の構成になっており、各段落もトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が守られています。これにより、非常に高い可読性が確保されています。

Diff内容との照合 ✓ PASS

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

記事内の変更前・変更後のコードブロックは、提供されたDiffの内容を正確に抜粋・反映しています。ファイルパスも一致しており、技術的な誤りはありません。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「ActiveSupport::EventReporter」「ペイロード構築」「フィルタリング」などの技術用語が、PRの文脈に沿って正確に使用されています。

説明の技術的正確性 ✓ PASS

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

「ペイロード構築前にフィルタリングを行う」「購読者がいなければ早期リターンする」といった説明は、Diff内のコードロジックと完全に一致しており、技術的に正確です。

事実の突合 ✓ PASS

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

記事内のすべての主張(例:最適化が機能していなかった背景、破壊的変更であることの認識)は、PRのDescriptionやDiff(CHANGELOG含む)によって裏付けられており、ハルシネーションは検出されませんでした。

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

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

記事内で言及されているPR番号(#56761, #55900)は正確であり、正しくリンクされています。

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

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

記事タイトル「EventReporterのペイロード構築を購読者フィルタリング後に実行」は、PRのタイトル「EventReporter: filter events before building the payload」の内容を的確に和訳・表現しています。

外部知識の正確性 ✓ PASS

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

記事の内容は提供されたPR情報に完全に準拠しており、バージョンサポート状況やリリース日程といったPR外の知識の追加はありません。

時間表現の正確性 ✓ PASS

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

PR Descriptionで述べられている現状の問題点(we now always pay...)を、記事では「...していた」と過去の事象として適切に表現しており、時間表現に歪曲はありません。