Class: SolidObjects::Web::Statistics

Inherits:
Object
  • Object
show all
Defined in:
lib/solid_objects/web/statistics.rb,
sig/generated/lib/solid_objects/web/statistics.rbs

Overview

The counts behind the dashboard and behind GET /stats. Both read the same object, so the polled JSON and the rendered page can never disagree about what a number means.

Constant Summary collapse

EFFECT_STATUSES =

Returns:

  • (Object)
%w[pending processing completed dead].freeze
BROADCAST_STATUSES =

Returns:

  • (Object)
%w[pending processing delivered dead].freeze
REMINDER_STATUSES =

Returns:

  • (Object)
%w[scheduled paused completed].freeze
PROCESS_STATES =

Returns:

  • (Object)
%w[running draining stopped].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(now: SolidObjects.database_adapter.database_now) ⇒ Statistics

Returns a new instance of Statistics.

RBS:

  • (?now: Time) -> void

Parameters:

  • now: (Time) (defaults to: SolidObjects.database_adapter.database_now)


19
20
21
# File 'lib/solid_objects/web/statistics.rb', line 19

def initialize(now: SolidObjects.database_adapter.database_now)
  @now = now
end

Instance Attribute Details

#nowObject (readonly)

RBS:

  • @now: Time

Returns:

  • (Object)


16
17
18
# File 'lib/solid_objects/web/statistics.rb', line 16

def now
  @now
end

Instance Method Details

#grouped(model, column, statuses) ⇒ Hash[Symbol, Integer]

A status the schema allows but the table does not currently hold still reports zero, so a row of counts keeps the same shape between polls.

RBS:

  • (untyped, Symbol, Array[String]) -> Hash[Symbol, Integer]

Parameters:

  • (Object)
  • (Symbol)
  • (Array[String])

Returns:

  • (Hash[Symbol, Integer])


72
73
74
75
# File 'lib/solid_objects/web/statistics.rb', line 72

def grouped(model, column, statuses)
  counts = model.group(column).count
  statuses.to_h { |status| [ status.to_sym, counts.fetch(status, 0) ] }
end

#instancesHash[Symbol, Integer]

RBS:

  • () -> Hash[Symbol, Integer]

Returns:

  • (Hash[Symbol, Integer])


38
39
40
41
42
43
44
# File 'lib/solid_objects/web/statistics.rb', line 38

def instances
  {
    total: Instance.count,
    paused: Instance.where.not(paused_at: nil).count,
    activated: Instance.where(activation_expires_at: now..).count
  }
end

#mailboxHash[Symbol, untyped]

The oldest ready message that is already due is the queue latency of this runtime: how far behind the workers are, in seconds.

RBS:

  • () -> Hash[Symbol, untyped]

Returns:

  • (Hash[Symbol, untyped])


49
50
51
52
53
54
55
56
57
58
# File 'lib/solid_objects/web/statistics.rb', line 49

def mailbox
  due = ReadyMessage.where(available_at: ..now)
  oldest = due.minimum(:available_at)
  {
    ready: ReadyMessage.count,
    due: due.count,
    claimed: ClaimedMessage.count,
    latency: oldest ? (now - oldest).round(3) : 0.0
  }
end

#remindersHash[Symbol, Integer]

RBS:

  • () -> Hash[Symbol, Integer]

Returns:

  • (Hash[Symbol, Integer])


61
62
63
64
65
# File 'lib/solid_objects/web/statistics.rb', line 61

def reminders
  grouped(Reminder, :status, REMINDER_STATUSES).merge(
    due: Reminder.where(status: "scheduled", next_run_at: ..now).count
  )
end

#to_hHash[Symbol, untyped]

RBS:

  • () -> Hash[Symbol, untyped]

Returns:

  • (Hash[Symbol, untyped])


24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/solid_objects/web/statistics.rb', line 24

def to_h
  {
    instances:,
    mailbox:,
    effects: grouped(Effect, :status, EFFECT_STATUSES),
    broadcasts: grouped(Broadcast, :status, BROADCAST_STATUSES),
    reminders:,
    dead_letters: { total: DeadLetter.count },
    processes: grouped(Process, :shutdown_state, PROCESS_STATES),
    server_time: now.utc.iso8601
  }
end