Class: Flightdeck::Overview

Inherits:
Object
  • Object
show all
Defined in:
app/models/flightdeck/overview.rb

Overview

Everything the Overview page shows, assembled from the same query objects the rest of the dashboard uses.

Defined Under Namespace

Classes: Tile

Constant Summary collapse

WINDOW =
24.hours
RECENT_FAILURES =
5
TOP_QUEUES =
6

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(now: Time.current) ⇒ Overview

Returns a new instance of Overview.



20
21
22
# File 'app/models/flightdeck/overview.rb', line 20

def initialize(now: Time.current)
  @now = now
end

Instance Attribute Details

#nowObject (readonly)

Returns the value of attribute now.



18
19
20
# File 'app/models/flightdeck/overview.rb', line 18

def now
  @now
end

Instance Method Details

#failed_24hObject



73
74
75
# File 'app/models/flightdeck/overview.rb', line 73

def failed_24h
  @failed_24h ||= counted("failed", WINDOW) { SolidQueue::FailedExecution.where(created_at: (now - WINDOW)..now) }
end

#failed_countObject



53
54
55
# File 'app/models/flightdeck/overview.rb', line 53

def failed_count
  @failed_count ||= JobsQuery.new(state: :failed).count
end

#failure_rateObject



121
122
123
124
125
126
# File 'app/models/flightdeck/overview.rb', line 121

def failure_rate
  total = processed_24h + failed_24h
  return nil if total.zero?

  (failed_24h.to_f / total * 100).round(1)
end

#in_progressObject



79
# File 'app/models/flightdeck/overview.rb', line 79

def in_progress = @in_progress ||= counted("in_progress") { SolidQueue::ClaimedExecution.all }

#max_queue_depthObject



37
38
39
# File 'app/models/flightdeck/overview.rb', line 37

def max_queue_depth
  @max_queue_depth ||= [ queues.map(&:depth).max.to_i, 1 ].max
end

#next_scheduled_atObject



81
82
83
84
85
# File 'app/models/flightdeck/overview.rb', line 81

def next_scheduled_at
  @next_scheduled_at ||= Cache.fetch("overview", "next_scheduled", expires_in: count_ttl) do
    SolidQueue::ScheduledExecution.minimum(:scheduled_at)
  end
end

#oldest_ready_ageObject



93
94
95
# File 'app/models/flightdeck/overview.rb', line 93

def oldest_ready_age
  oldest_ready_at && now - oldest_ready_at
end

#oldest_ready_atObject



87
88
89
90
91
# File 'app/models/flightdeck/overview.rb', line 87

def oldest_ready_at
  @oldest_ready_at ||= Cache.fetch("overview", "oldest_ready", expires_in: count_ttl) do
    SolidQueue::ReadyExecution.minimum(:created_at)
  end
end

#processed_24hObject

--- counts ---------------------------------------------------------------



63
64
65
# File 'app/models/flightdeck/overview.rb', line 63

def processed_24h
  @processed_24h ||= counted("processed", WINDOW) { SolidQueue::Job.where(finished_at: (now - WINDOW)..now) }
end

#processed_deltaObject



128
129
130
131
132
# File 'app/models/flightdeck/overview.rb', line 128

def processed_delta
  return nil if processed_prior_24h.zero?

  ((processed_24h - processed_prior_24h).to_f / processed_prior_24h * 100).round(1)
end

#processed_prior_24hObject



67
68
69
70
71
# File 'app/models/flightdeck/overview.rb', line 67

def processed_prior_24h
  @processed_prior_24h ||= counted("processed_prior", WINDOW) do
    SolidQueue::Job.where(finished_at: (now - (WINDOW * 2))...(now - WINDOW))
  end
end

#queuesObject



33
34
35
# File 'app/models/flightdeck/overview.rb', line 33

def queues
  @queues ||= QueueStats.new.rows.sort_by { |row| -row.depth }.first(TOP_QUEUES)
end

#ready_nowObject



77
# File 'app/models/flightdeck/overview.rb', line 77

def ready_now = @ready_now ||= counted("ready") { SolidQueue::ReadyExecution.all }

#recent_failuresObject



49
50
51
# File 'app/models/flightdeck/overview.rb', line 49

def recent_failures
  @recent_failures ||= JobsQuery.new(state: :failed, limit: RECENT_FAILURES).rows
end

#registryObject



57
58
59
# File 'app/models/flightdeck/overview.rb', line 57

def registry
  @registry ||= ProcessRegistry.new
end

#scheduledObject



78
# File 'app/models/flightdeck/overview.rb', line 78

def scheduled = @scheduled ||= counted("scheduled") { SolidQueue::ScheduledExecution.all }

#series(window: Metrics::Series::DEFAULT_WINDOW) ⇒ Object



28
29
30
31
# File 'app/models/flightdeck/overview.rb', line 28

def series(window: Metrics::Series::DEFAULT_WINDOW)
  @series ||= {}
  @series[window.to_s] ||= Metrics::Series.new(window: window, now: now)
end

#slotsObject

Total worker capacity, summed from each worker's registered thread pool size. Returns nil when no worker reported one, so the tile can omit the denominator rather than divide by a number it invented.

A worker that has stopped sending heartbeats is not capacity, whatever its metadata still says, so dead workers are excluded — otherwise utilization reads low precisely when the fleet is in trouble.



104
105
106
107
108
109
110
111
112
113
# File 'app/models/flightdeck/overview.rb', line 104

def slots
  @slots ||= begin
    sizes = registry.nodes.filter_map do |node|
      next unless node.claims_executions? && !node.dead?

      Integer(node..symbolize_keys[:thread_pool_size], exception: false)
    end
    sizes.any? ? sizes.sum : nil
  end
end

#sparkline_for(queue_name) ⇒ Object



45
46
47
# File 'app/models/flightdeck/overview.rb', line 45

def sparkline_for(queue_name)
  Metrics::Sparkline.new(sparklines[queue_name] || [])
end

#sparklinesObject



41
42
43
# File 'app/models/flightdeck/overview.rb', line 41

def sparklines
  @sparklines ||= Metrics::Series.queue_sparklines(now: now)
end

#tilesObject



24
25
26
# File 'app/models/flightdeck/overview.rb', line 24

def tiles
  [ processed_tile, failed_tile, ready_tile, scheduled_tile, in_progress_tile, oldest_ready_tile ]
end

#utilizationObject



115
116
117
118
119
# File 'app/models/flightdeck/overview.rb', line 115

def utilization
  return nil if slots.nil? || slots.zero?

  (in_progress.to_f / slots * 100).round
end