[privacy] surface local filtered-count request summary sink

In-process, thread-safe last-request-summary sink (per account_id) with a
public last_request_summary(account_id:) reader so FilteredCountInstrumentation's
documented local observability signals are consumable instead of discarded.
No APM/New Relic or any off-box egress; sink and reader stay fully in-process.
Adds regression specs asserting the completed summary (status, counts,
duration) is readable and an unknown account returns nil.
This commit is contained in:
Kunthawat Greethong
2026-08-16 07:36:06 +07:00
parent c9c0a749c3
commit 2ef6fa554b
2 changed files with 44 additions and 0 deletions

View File

@@ -65,8 +65,31 @@ class Conversations::UnreadCounts::FilteredCountInstrumentation
record_increment_summary(operation, attributes) if aggregated_increment?(operation)
end
# Local-only observability sink. Consumers may read the most recent completed
# request summary for an account in this process; nothing is emitted off-box.
def last_request_summary(account_id:)
sink = summary_sink
summary = sink[:lock].synchronize { sink[:store][account_id] }
summary&.dup
end
private
def summary_sink
init_lock = (@initialization_lock ||= Mutex.new)
init_lock.synchronize do
@summary_store_lock ||= Mutex.new
@summary_store ||= {}
end
{ lock: @summary_store_lock, store: @summary_store }
end
def store_request_summary(summary)
key = summary[:account_id]
sink = summary_sink
sink[:lock].synchronize { sink[:store][key] = summary.dup }
end
def record_observation(operation, attributes, started_at, status:)
duration_ms = elapsed_ms_since(started_at)
record_observation_summary(operation, attributes, status: status)
@@ -76,6 +99,7 @@ class Conversations::UnreadCounts::FilteredCountInstrumentation
def record_request_summary(summary, status, started_at)
summary[:status] = status
summary[:duration_ms] = elapsed_ms_since(started_at)
store_request_summary(summary)
end
def request_summary(account_id)