Class: Alplus::PendingWindow
- Inherits:
-
Object
- Object
- Alplus::PendingWindow
- Defined in:
- lib/alplus/pending_window.rb
Overview
The post-error log window (issue #47): a built exception item is held
here for a short, bounded window before delivery, and log-line
breadcrumbs recorded on the SAME thread during the window are appended
to it, marked data: { after_error: true }.
Same-thread attribution is the correctness rule: under a concurrent
server, another request's log lines must never pollute this error's
timeline. Rails logs the unhandled exception (DebugExceptions) on the
request thread AFTER RackMiddleware re-raises, which is exactly the
window this class keeps open — a request-end seal would run too early
to see that line.
One lazily-spawned sealer thread sleeps until the earliest deadline and
seals due entries; it exits when the list drains and respawns on the
next hold. seal_all! (called by Client#flush/#close) seals
everything immediately — the window delays delivery, never loses events.
Defined Under Namespace
Classes: Entry
Constant Summary collapse
- MAX_AFTER_ERROR_BREADCRUMBS =
20- MAX_TOTAL_BREADCRUMBS =
The server ceiling (
Envelope::SERVER_MAX_BREADCRUMBS). Envelope::SERVER_MAX_BREADCRUMBS
Instance Method Summary collapse
- #enabled? ⇒ Boolean
- #hold(item) ⇒ Object
-
#initialize(window_ms, &deliver) ⇒ PendingWindow
constructor
A new instance of PendingWindow.
-
#notify_log_breadcrumb(crumb) ⇒ Object
Appends a log-line breadcrumb to every pending entry captured on the calling thread, within the per-entry and total bounds.
- #seal_all! ⇒ Object
Constructor Details
#initialize(window_ms, &deliver) ⇒ PendingWindow
Returns a new instance of PendingWindow.
27 28 29 30 31 32 33 |
# File 'lib/alplus/pending_window.rb', line 27 def initialize(window_ms, &deliver) @window_ms = window_ms @deliver = deliver @entries = [] @mutex = Mutex.new @sealer = nil end |
Instance Method Details
#enabled? ⇒ Boolean
35 36 37 |
# File 'lib/alplus/pending_window.rb', line 35 def enabled? @window_ms.positive? end |
#hold(item) ⇒ Object
39 40 41 42 43 |
# File 'lib/alplus/pending_window.rb', line 39 def hold(item) entry = Entry.new(item: item, thread: Thread.current, deadline: monotonic_now + (@window_ms / 1000.0), appended: 0) @mutex.synchronize { @entries << entry } ensure_sealer_running end |
#notify_log_breadcrumb(crumb) ⇒ Object
Appends a log-line breadcrumb to every pending entry captured on the calling thread, within the per-entry and total bounds. Never raises.
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/alplus/pending_window.rb', line 47 def (crumb) @mutex.synchronize do @entries.each do |entry| next unless entry.thread == Thread.current next if entry.appended >= MAX_AFTER_ERROR_BREADCRUMBS crumbs = (entry.item[:breadcrumbs] ||= []) next if crumbs.length >= MAX_TOTAL_BREADCRUMBS crumbs << crumb.merge(data: (crumb[:data] || {}).merge(after_error: true)) entry.appended += 1 end end nil rescue StandardError nil end |
#seal_all! ⇒ Object
65 66 67 68 |
# File 'lib/alplus/pending_window.rb', line 65 def seal_all! entries = @mutex.synchronize { @entries.slice!(0..) } entries.each { |entry| @deliver.call(entry.item) } end |