Class: RailsErrorDashboard::Commands::FlushStormCounts

Inherits:
Object
  • Object
show all
Defined in:
lib/rails_error_dashboard/commands/flush_storm_counts.rb

Overview

Command: Reconcile counted-not-stored storm events onto ErrorLog rows and maintain the storm_events episode record.

Runs in a background job (DB allowed). For each counted fingerprint:

1. Recompute the canonical error_hash from the stored identity parts
   (the gate's key deliberately omits application_id — resolved here)
2. Unresolved match  → single UPDATE: occurrence_count += N
3. Resolved match    → reopen (mirrors FindOrIncrementError semantics)
4. No match          → create a minimal ErrorLog from the exemplar

Counts are exact. Notifications are NOT dispatched from here — during a storm they’re suppressed by design; the storm notification covers it.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(entries:, overflow: 0, episode: nil) ⇒ FlushStormCounts

Returns a new instance of FlushStormCounts.



22
23
24
25
26
# File 'lib/rails_error_dashboard/commands/flush_storm_counts.rb', line 22

def initialize(entries:, overflow: 0, episode: nil)
  @entries = Array(entries)
  @overflow = overflow.to_i
  @episode = episode
end

Class Method Details

.call(entries:, overflow: 0, episode: nil) ⇒ Object



18
19
20
# File 'lib/rails_error_dashboard/commands/flush_storm_counts.rb', line 18

def self.call(entries:, overflow: 0, episode: nil)
  new(entries: entries, overflow: overflow, episode: episode).call
end

Instance Method Details

#callObject



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/rails_error_dashboard/commands/flush_storm_counts.rb', line 28

def call
  application = resolve_application
  counted = 0

  @entries.each do |entry|
    entry = entry.with_indifferent_access if entry.respond_to?(:with_indifferent_access)
    counted += reconcile_entry(entry, application)
  rescue => e
    # A corrupt (non-Hash) entry must not abort the whole batch — and the
    # log line itself must not assume `entry` is subscriptable (an Integer
    # from a broken serializer would raise again here, escaping this rescue).
    error_class = entry.is_a?(Hash) ? entry["error_class"] : entry.class
    RailsErrorDashboard::Logger.error(
      "[RailsErrorDashboard] Storm count reconcile failed for #{error_class}: #{e.class} - #{e.message}"
    )
  end

  upsert_storm_event(counted)
  { success: true, reconciled: counted, overflow: @overflow }
rescue => e
  RailsErrorDashboard::Logger.error(
    "[RailsErrorDashboard] FlushStormCounts failed: #{e.class} - #{e.message}"
  )
  { success: false, error: "#{e.class}: #{e.message}" }
end