Class: ChronoForge::Dashboard::WaitStatesController

Inherits:
BaseController
  • Object
show all
Defined in:
app/controllers/chrono_forge/dashboard/wait_states_controller.rb

Constant Summary collapse

CAP =

Bound the scan: at scale there can be tens of thousands of idle workflows, so we examine at most CAP (oldest first) and resolve their waits in a single batch query rather than one query per row.

500

Instance Method Summary collapse

Instance Method Details

#indexObject



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'app/controllers/chrono_forge/dashboard/wait_states_controller.rb', line 9

def index
  idle = ChronoForge::Workflow
    .where(state: ChronoForge::Workflow.states[:idle])
    .order(id: :asc)
    .limit(CAP + 1)
    .to_a
  @capped = idle.size > CAP
  idle = idle.first(CAP)

  waits = WaitStatePresenter.active_map(idle)
  @waits = idle.filter_map { |wf| {workflow: wf, wait: waits[wf.id]} if waits[wf.id] }
    .sort_by { |h| h[:wait].waiting_since || Time.current }

  # The headline signal: the oldest unresolved continue_if (event) wait per
  # class. These never time out or self-resume — a webhook that never
  # arrives sits here forever — so the oldest one per class is what an
  # operator must chase down.
  @oldest_event_by_class = @waits
    .select { |h| h[:wait].event_wait? }
    .group_by { |h| h[:workflow].job_class }
    .transform_values { |rows| rows.min_by { |h| h[:wait].waiting_since || Time.current } }
    .values
    .sort_by { |h| h[:wait].waiting_since || Time.current }

  @threshold = ChronoForge::Dashboard.config.long_wait_threshold
  @cap = CAP
end