Module: OpenLoam::EventLog
- Defined in:
- lib/open_loam/event_log.rb
Overview
Captures every published event as a queryable OpenLoam::EventRecord row — the capture half of the event system, where OpenLoam::DurableEvents is the delivery half ("durability is of DELIVERY, not CAPTURE").
Capture is ON by default and captures everything but OpenLoam.uncaptured_events. That inverts OpenLoam.broadcast_events on purpose; see ADR 0007 for why, and for why this stayed in-gem rather than adopting Rails Event Store.
Capture runs INLINE in the publisher's thread, so a failed insert propagates into whatever published the event. Deliberate — do not rescue it. Swallowing the error re-opens the silent gap this module exists to close.
Constant Summary collapse
- PRUNE_KEY =
"open_loam_event_log_prune".freeze
Class Method Summary collapse
-
.capturable?(event_name) ⇒ Boolean
Exclusion is the only knob, because pattern_matches? has no match-all spelling ("" is an exact match on the empty name).
- .capture(event_name, payload) ⇒ Object
-
.prune(now: Time.current) ⇒ Object
delete_all, NOT destroy_all: rows are readonly once persisted, and destroy on a readonly record raises ActiveRecord::ReadOnlyRecord.
-
.read(name_or_prefix = nil, since: nil, limit: nil) ⇒ Object
name_or_prefix takes an exact event name or a trailing-dot domain prefix, the same rule as Events.subscribe.
-
.replay(name_or_prefix = nil, since: nil, limit: nil, &handler) ⇒ Object
A re-read of history, NOT a second publish: nothing else on the bus fires and a replayed event is not re-captured.
-
.subscribe! ⇒ Object
Idempotent: subscribing twice would capture every event twice.
Class Method Details
.capturable?(event_name) ⇒ Boolean
Exclusion is the only knob, because pattern_matches? has no match-all spelling ("" is an exact match on the empty name). Do not add an allow-list: capture-all has to stay the absence of configuration.
25 26 27 28 29 30 31 |
# File 'lib/open_loam/event_log.rb', line 25 def capturable?(event_name) OpenLoam.uncaptured_events.none? do |pattern| next false if OpenLoam::Overrides.disabled?(:uncaptured_events, pattern) # an app can re-enable a default exclusion OpenLoam::Events.pattern_matches?(pattern, event_name) end end |
.capture(event_name, payload) ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/open_loam/event_log.rb', line 33 def capture(event_name, payload) return unless capturable?(event_name) tenant = OpenLoam::Tenant.find_by(id: payload[:tenant_id]) return if tenant.nil? # nil-tenant events are not captured (as Webhooks.dispatch / DurableEvents.capture) OpenLoam.as_tenant(tenant) do OpenLoam::EventRecord.create!( name: event_name.to_s, payload: payload.transform_keys(&:to_s), occurred_at: Time.current ) end end |
.prune(now: Time.current) ⇒ Object
delete_all, NOT destroy_all: rows are readonly once persisted, and destroy on a readonly record raises ActiveRecord::ReadOnlyRecord.
69 70 71 72 73 74 |
# File 'lib/open_loam/event_log.rb', line 69 def prune(now: Time.current) retention = OpenLoam.event_log_retention return 0 if retention.nil? OpenLoam::EventRecord.where(occurred_at: ...(now - retention)).delete_all end |
.read(name_or_prefix = nil, since: nil, limit: nil) ⇒ Object
name_or_prefix takes an exact event name or a trailing-dot domain prefix, the same rule as Events.subscribe. Oldest first.
50 51 52 53 54 55 56 |
# File 'lib/open_loam/event_log.rb', line 50 def read(name_or_prefix = nil, since: nil, limit: nil) scope = OpenLoam::EventRecord.chronological scope = scope.matching(name_or_prefix) if name_or_prefix.present? scope = scope.where(occurred_at: since..) if since scope = scope.limit(limit) if limit scope end |
.replay(name_or_prefix = nil, since: nil, limit: nil, &handler) ⇒ Object
A re-read of history, NOT a second publish: nothing else on the bus fires and a replayed event is not re-captured. Handlers must be idempotent, and get string payload keys (from the row) where a live subscriber got symbols.
61 62 63 64 65 |
# File 'lib/open_loam/event_log.rb', line 61 def replay(name_or_prefix = nil, since: nil, limit: nil, &handler) read(name_or_prefix, since: since, limit: limit).each do |record| handler.call(record.name, record.payload_hash) end end |
.subscribe! ⇒ Object
Idempotent: subscribing twice would capture every event twice.
18 19 20 |
# File 'lib/open_loam/event_log.rb', line 18 def subscribe! @subscription ||= OpenLoam::Events.subscribe_all { |event_name, payload| capture(event_name, payload) } end |