flightdeck 0.5.3 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +8 -199
- metadata +12 -96
- data/MIT-LICENSE +0 -21
- data/app/assets/flightdeck/flightdeck-3967b9e6c506.css +0 -3
- data/app/assets/flightdeck/flightdeck-3aac23f80afe.js +0 -414
- data/app/assets/flightdeck/manifest.json +0 -16
- data/app/controllers/concerns/flightdeck/toasts.rb +0 -35
- data/app/controllers/flightdeck/application_controller.rb +0 -110
- data/app/controllers/flightdeck/assets_controller.rb +0 -39
- data/app/controllers/flightdeck/jobs/actions_controller.rb +0 -166
- data/app/controllers/flightdeck/jobs/discards_controller.rb +0 -43
- data/app/controllers/flightdeck/jobs/retries_controller.rb +0 -22
- data/app/controllers/flightdeck/jobs_controller.rb +0 -39
- data/app/controllers/flightdeck/overview_controller.rb +0 -11
- data/app/controllers/flightdeck/processes_controller.rb +0 -54
- data/app/controllers/flightdeck/queues_controller.rb +0 -56
- data/app/controllers/flightdeck/recurring_tasks_controller.rb +0 -51
- data/app/helpers/flightdeck/application_helper.rb +0 -85
- data/app/helpers/flightdeck/infrastructure_helper.rb +0 -24
- data/app/helpers/flightdeck/jobs_helper.rb +0 -117
- data/app/helpers/flightdeck/metrics_helper.rb +0 -49
- data/app/models/flightdeck/arguments_preview.rb +0 -95
- data/app/models/flightdeck/bulk_action.rb +0 -83
- data/app/models/flightdeck/cache.rb +0 -51
- data/app/models/flightdeck/cron_schedule.rb +0 -102
- data/app/models/flightdeck/duration.rb +0 -23
- data/app/models/flightdeck/error_summary.rb +0 -64
- data/app/models/flightdeck/grouped_failures.rb +0 -24
- data/app/models/flightdeck/job_detail.rb +0 -156
- data/app/models/flightdeck/job_row.rb +0 -103
- data/app/models/flightdeck/jobs_query.rb +0 -233
- data/app/models/flightdeck/metrics/bar_chart.rb +0 -49
- data/app/models/flightdeck/metrics/chart.rb +0 -111
- data/app/models/flightdeck/metrics/line_chart.rb +0 -63
- data/app/models/flightdeck/metrics/series.rb +0 -165
- data/app/models/flightdeck/metrics/sparkline.rb +0 -45
- data/app/models/flightdeck/metrics/time_bucket.rb +0 -95
- data/app/models/flightdeck/overview.rb +0 -210
- data/app/models/flightdeck/process_registry.rb +0 -102
- data/app/models/flightdeck/queue_stats.rb +0 -86
- data/app/models/flightdeck/recurring_catalog.rb +0 -114
- data/app/views/flightdeck/jobs/_failed_row.html.erb +0 -33
- data/app/views/flightdeck/jobs/_filter_bar.html.erb +0 -29
- data/app/views/flightdeck/jobs/_list.html.erb +0 -94
- data/app/views/flightdeck/jobs/_pager.html.erb +0 -22
- data/app/views/flightdeck/jobs/_row.html.erb +0 -23
- data/app/views/flightdeck/jobs/_state_tabs.html.erb +0 -10
- data/app/views/flightdeck/jobs/index.html.erb +0 -10
- data/app/views/flightdeck/jobs/show.html.erb +0 -100
- data/app/views/flightdeck/metrics/_bar_chart.html.erb +0 -34
- data/app/views/flightdeck/metrics/_line_chart.html.erb +0 -38
- data/app/views/flightdeck/metrics/_range_control.html.erb +0 -7
- data/app/views/flightdeck/metrics/_sparkline.html.erb +0 -9
- data/app/views/flightdeck/overview/_completion.html.erb +0 -19
- data/app/views/flightdeck/overview/_failures.html.erb +0 -28
- data/app/views/flightdeck/overview/_fleet.html.erb +0 -21
- data/app/views/flightdeck/overview/_queues.html.erb +0 -41
- data/app/views/flightdeck/overview/_throughput.html.erb +0 -23
- data/app/views/flightdeck/overview/_tiles.html.erb +0 -14
- data/app/views/flightdeck/overview/index.html.erb +0 -29
- data/app/views/flightdeck/processes/_fleet.html.erb +0 -54
- data/app/views/flightdeck/processes/_row.html.erb +0 -28
- data/app/views/flightdeck/processes/index.html.erb +0 -5
- data/app/views/flightdeck/queues/_cards.html.erb +0 -46
- data/app/views/flightdeck/queues/index.html.erb +0 -5
- data/app/views/flightdeck/recurring_tasks/_table.html.erb +0 -53
- data/app/views/flightdeck/recurring_tasks/index.html.erb +0 -5
- data/app/views/flightdeck/shared/_toast.html.erb +0 -7
- data/app/views/flightdeck/shared/refresh.turbo_stream.erb +0 -14
- data/app/views/layouts/flightdeck/application.html.erb +0 -110
- data/config/routes.rb +0 -40
- data/lib/flightdeck/assets.rb +0 -72
- data/lib/flightdeck/configuration.rb +0 -82
- data/lib/flightdeck/engine.rb +0 -31
- data/lib/flightdeck/version.rb +0 -5
- data/lib/flightdeck.rb +0 -31
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
<svg class="fd-chart" viewBox="0 0 <%= chart.width %> <%= chart.height %>"
|
|
2
|
-
preserveAspectRatio="xMidYMid meet" role="img"
|
|
3
|
-
aria-label="Average time to completion <%= chart.window.subtitle %>">
|
|
4
|
-
<% chart.gridlines.each do |line| %>
|
|
5
|
-
<line x1="<%= chart.plot_left %>" x2="<%= chart.plot_right %>"
|
|
6
|
-
y1="<%= line[:y] %>" y2="<%= line[:y] %>" class="fd-chart-grid"/>
|
|
7
|
-
<text x="<%= chart.plot_left - 6 %>" y="<%= line[:y] + 3 %>" class="fd-chart-label" text-anchor="end"><%= line[:label] %></text>
|
|
8
|
-
<% end %>
|
|
9
|
-
|
|
10
|
-
<% chart.segments.each do |segment| %>
|
|
11
|
-
<path d="<%= chart.area_path(segment) %>" class="fd-chart-area"/>
|
|
12
|
-
<path d="<%= chart.line_path(segment) %>" class="fd-chart-line"/>
|
|
13
|
-
<% end %>
|
|
14
|
-
|
|
15
|
-
<% chart.markers.each do |marker| %>
|
|
16
|
-
<g>
|
|
17
|
-
<title><%= marker[:title] %></title>
|
|
18
|
-
<circle cx="<%= marker[:x] %>" cy="<%= marker[:y] %>" r="7" fill="transparent"/>
|
|
19
|
-
</g>
|
|
20
|
-
<% end %>
|
|
21
|
-
|
|
22
|
-
<% if chart.last_marker %>
|
|
23
|
-
<circle cx="<%= chart.last_marker[:x] %>" cy="<%= chart.last_marker[:y] %>"
|
|
24
|
-
r="<%= Flightdeck::Metrics::LineChart::DOT_RADIUS %>" class="fd-chart-dot"/>
|
|
25
|
-
<% end %>
|
|
26
|
-
|
|
27
|
-
<line x1="<%= chart.plot_left %>" x2="<%= chart.plot_right %>"
|
|
28
|
-
y1="<%= chart.plot_bottom %>" y2="<%= chart.plot_bottom %>" class="fd-chart-axis"/>
|
|
29
|
-
|
|
30
|
-
<% chart.x_ticks.each do |tick| %>
|
|
31
|
-
<text x="<%= tick[:x] %>" y="<%= chart.height - 6 %>" class="fd-chart-label" text-anchor="middle"><%= tick[:label] %></text>
|
|
32
|
-
<% end %>
|
|
33
|
-
|
|
34
|
-
<% unless chart.any_data? %>
|
|
35
|
-
<text x="<%= chart.plot_left + (chart.plot_width / 2) %>" y="<%= chart.plot_top + (chart.plot_height / 2) %>"
|
|
36
|
-
class="fd-chart-label" text-anchor="middle">no jobs finished in this window</text>
|
|
37
|
-
<% end %>
|
|
38
|
-
</svg>
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
<% if sparkline.any? %>
|
|
2
|
-
<svg class="fd-sparkline" viewBox="0 0 <%= sparkline.width %> <%= sparkline.height %>"
|
|
3
|
-
preserveAspectRatio="none" aria-hidden="true">
|
|
4
|
-
<path d="<%= sparkline.area_path %>" class="fd-spark-area"/>
|
|
5
|
-
<path d="<%= sparkline.line_path %>" class="fd-spark-line" vector-effect="non-scaling-stroke"/>
|
|
6
|
-
</svg>
|
|
7
|
-
<% else %>
|
|
8
|
-
<div class="fd-spark-placeholder" aria-hidden="true"></div>
|
|
9
|
-
<% end %>
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
<div class="fd-card">
|
|
2
|
-
<div class="fd-card-hd">
|
|
3
|
-
<h3>Time to completion</h3>
|
|
4
|
-
<span class="sub">enqueue → finish, average <%= window.subtitle %></span>
|
|
5
|
-
<div class="right">
|
|
6
|
-
<div class="fd-legend"><span><i class="fd-swatch-s3"></i>Average</span></div>
|
|
7
|
-
</div>
|
|
8
|
-
</div>
|
|
9
|
-
<div class="fd-chart-body">
|
|
10
|
-
<%= render "flightdeck/metrics/line_chart",
|
|
11
|
-
chart: Flightdeck::Metrics::LineChart.new(points: series.completion_time, window: window) %>
|
|
12
|
-
</div>
|
|
13
|
-
<%# Deliberately not "time to start": Solid Queue deletes the claim row when a
|
|
14
|
-
job finishes, so historical time-to-start cannot be recovered. %>
|
|
15
|
-
<div class="fd-chart-note">
|
|
16
|
-
Measured from enqueue to finish. Time spent waiting and time spent running are not
|
|
17
|
-
separable after the fact.
|
|
18
|
-
</div>
|
|
19
|
-
</div>
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
<div class="fd-card">
|
|
2
|
-
<div class="fd-card-hd">
|
|
3
|
-
<h3>Recent failures</h3>
|
|
4
|
-
<div class="right">
|
|
5
|
-
<%= link_to "View all #{fd_count(overview.failed_count)}", jobs_path(state: :failed), class: "fd-btn sm" %>
|
|
6
|
-
</div>
|
|
7
|
-
</div>
|
|
8
|
-
<div class="fd-scroll-x">
|
|
9
|
-
<table class="fd-data">
|
|
10
|
-
<tbody>
|
|
11
|
-
<% if overview.recent_failures.empty? %>
|
|
12
|
-
<tr><td><div class="fd-empty">No failures. Nothing to see here.</div></td></tr>
|
|
13
|
-
<% else %>
|
|
14
|
-
<% overview.recent_failures.each do |row| %>
|
|
15
|
-
<tr>
|
|
16
|
-
<td class="cls">
|
|
17
|
-
<%= link_to row.class_name, job_path(row.id, state: :failed) %>
|
|
18
|
-
<div class="args"><%= row.error_summary.present? ? row.error_summary.to_s : "—" %></div>
|
|
19
|
-
</td>
|
|
20
|
-
<td><%= fd_queue_badge(row.queue_name) %></td>
|
|
21
|
-
<td class="dim num"><%= row.failed_at ? fd_ago(row.failed_at) : "—" %></td>
|
|
22
|
-
</tr>
|
|
23
|
-
<% end %>
|
|
24
|
-
<% end %>
|
|
25
|
-
</tbody>
|
|
26
|
-
</table>
|
|
27
|
-
</div>
|
|
28
|
-
</div>
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
<div class="fd-card">
|
|
2
|
-
<div class="fd-card-hd">
|
|
3
|
-
<h3>Fleet</h3>
|
|
4
|
-
<span class="sub"><%= pluralize(registry.total, "process") %> · last heartbeats</span>
|
|
5
|
-
<div class="right"><%= link_to "Processes", processes_path, class: "fd-btn sm" %></div>
|
|
6
|
-
</div>
|
|
7
|
-
<div class="fd-health-strip">
|
|
8
|
-
<% if registry.nodes.empty? %>
|
|
9
|
-
<div class="fd-empty">No Solid Queue processes are registered.</div>
|
|
10
|
-
<% else %>
|
|
11
|
-
<% registry.nodes.each do |node| %>
|
|
12
|
-
<span class="fd-proc-chip" title="<%= node.name %> · heartbeat <%= fd_ago(node.last_heartbeat_at) %>">
|
|
13
|
-
<span class="fd-led <%= node.freshness %>"></span>
|
|
14
|
-
<%= node.kind.downcase %> · <%= node.hostname.presence || "unknown host" %><%
|
|
15
|
-
%><% if node.claims_executions? && node.freshness == :fresh %> · <%= node.claimed_count %> claimed<%
|
|
16
|
-
%><% else %> · heartbeat <%= fd_ago(node.last_heartbeat_at) %><% end %>
|
|
17
|
-
</span>
|
|
18
|
-
<% end %>
|
|
19
|
-
<% end %>
|
|
20
|
-
</div>
|
|
21
|
-
</div>
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
<div class="fd-card">
|
|
2
|
-
<div class="fd-card-hd">
|
|
3
|
-
<h3>Queues</h3>
|
|
4
|
-
<div class="right"><%= link_to "View all", queues_path, class: "fd-btn sm" %></div>
|
|
5
|
-
</div>
|
|
6
|
-
<div class="fd-scroll-x">
|
|
7
|
-
<table class="fd-data">
|
|
8
|
-
<thead>
|
|
9
|
-
<tr>
|
|
10
|
-
<th>Queue</th>
|
|
11
|
-
<th class="num">Depth</th>
|
|
12
|
-
<th class="num">Latency</th>
|
|
13
|
-
<th>Last <%= Flightdeck::Metrics::Series::SPARKLINE_HOURS %>h</th>
|
|
14
|
-
<th style="width:90px"></th>
|
|
15
|
-
</tr>
|
|
16
|
-
</thead>
|
|
17
|
-
<tbody>
|
|
18
|
-
<% if overview.queues.empty? %>
|
|
19
|
-
<tr><td colspan="5"><div class="fd-empty">No queues yet.</div></td></tr>
|
|
20
|
-
<% else %>
|
|
21
|
-
<% overview.queues.each do |queue| %>
|
|
22
|
-
<tr>
|
|
23
|
-
<td class="cls">
|
|
24
|
-
<%= link_to queue.name, queues_path %>
|
|
25
|
-
<% if queue.paused? %><span class="fd-pill paused">PAUSED</span><% end %>
|
|
26
|
-
</td>
|
|
27
|
-
<td class="num"><%= number_with_delimiter(queue.depth) %></td>
|
|
28
|
-
<td class="num dim"><%= queue.latency ? fd_duration(queue.latency) : "—" %></td>
|
|
29
|
-
<td><%= render "flightdeck/metrics/sparkline", sparkline: overview.sparkline_for(queue.name) %></td>
|
|
30
|
-
<td>
|
|
31
|
-
<div class="fd-depth-bar">
|
|
32
|
-
<i style="width: <%= fd_depth_share(queue.depth, overview.max_queue_depth) %>%"></i>
|
|
33
|
-
</div>
|
|
34
|
-
</td>
|
|
35
|
-
</tr>
|
|
36
|
-
<% end %>
|
|
37
|
-
<% end %>
|
|
38
|
-
</tbody>
|
|
39
|
-
</table>
|
|
40
|
-
</div>
|
|
41
|
-
</div>
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
<div class="fd-card">
|
|
2
|
-
<div class="fd-card-hd">
|
|
3
|
-
<h3>Throughput</h3>
|
|
4
|
-
<span class="sub">jobs finished <%= window.subtitle %></span>
|
|
5
|
-
<div class="right">
|
|
6
|
-
<div class="fd-legend">
|
|
7
|
-
<span><i class="fd-swatch-s1"></i>Succeeded</span>
|
|
8
|
-
<span><i class="fd-swatch-s2"></i>Failed</span>
|
|
9
|
-
</div>
|
|
10
|
-
<%= render "flightdeck/metrics/range_control", window: window %>
|
|
11
|
-
</div>
|
|
12
|
-
</div>
|
|
13
|
-
<div class="fd-chart-body">
|
|
14
|
-
<%= render "flightdeck/metrics/bar_chart",
|
|
15
|
-
chart: Flightdeck::Metrics::BarChart.new(points: series.throughput, window: window) %>
|
|
16
|
-
</div>
|
|
17
|
-
<% if series.truncated_by_retention? %>
|
|
18
|
-
<div class="fd-chart-note">
|
|
19
|
-
Finished jobs are retained for <%= fd_duration(series.retention) %>, which is shorter than this
|
|
20
|
-
window — the oldest buckets undercount.
|
|
21
|
-
</div>
|
|
22
|
-
<% end %>
|
|
23
|
-
</div>
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
<div class="fd-tiles">
|
|
2
|
-
<% overview.tiles.each do |tile| %>
|
|
3
|
-
<div class="fd-card fd-tile">
|
|
4
|
-
<div class="lbl"><%= tile.label %></div>
|
|
5
|
-
<div class="val">
|
|
6
|
-
<%= tile.value %><%
|
|
7
|
-
%><% if tile.unit %><small><%= tile.unit %></small><% end %>
|
|
8
|
-
</div>
|
|
9
|
-
<div class="delta <%= fd_delta_class(tile) %>">
|
|
10
|
-
<%= fd_trend_glyph(tile.trend) %> <%= tile.detail %>
|
|
11
|
-
</div>
|
|
12
|
-
</div>
|
|
13
|
-
<% end %>
|
|
14
|
-
</div>
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
<% content_for :page_title, "Overview" %>
|
|
2
|
-
|
|
3
|
-
<%= fd_refresh_frame "fd-tiles", url: root_path(range: @window.key) do %>
|
|
4
|
-
<%= render "flightdeck/overview/tiles", overview: @overview %>
|
|
5
|
-
<% end %>
|
|
6
|
-
|
|
7
|
-
<div class="fd-grid-2">
|
|
8
|
-
<%= fd_refresh_frame "fd-throughput", url: root_path(range: @window.key), interval: fd_chart_poll_ms do %>
|
|
9
|
-
<%= render "flightdeck/overview/throughput", series: @series, window: @window %>
|
|
10
|
-
<% end %>
|
|
11
|
-
|
|
12
|
-
<%= fd_refresh_frame "fd-completion", url: root_path(range: @window.key), interval: fd_chart_poll_ms do %>
|
|
13
|
-
<%= render "flightdeck/overview/completion", series: @series, window: @window %>
|
|
14
|
-
<% end %>
|
|
15
|
-
</div>
|
|
16
|
-
|
|
17
|
-
<div class="fd-grid-2b">
|
|
18
|
-
<%= fd_refresh_frame "fd-overview-queues", url: root_path(range: @window.key) do %>
|
|
19
|
-
<%= render "flightdeck/overview/queues", overview: @overview %>
|
|
20
|
-
<% end %>
|
|
21
|
-
|
|
22
|
-
<%= fd_refresh_frame "fd-overview-failures", url: root_path(range: @window.key) do %>
|
|
23
|
-
<%= render "flightdeck/overview/failures", overview: @overview %>
|
|
24
|
-
<% end %>
|
|
25
|
-
</div>
|
|
26
|
-
|
|
27
|
-
<%= fd_refresh_frame "fd-fleet", url: root_path(range: @window.key), class: "fd-block" do %>
|
|
28
|
-
<%= render "flightdeck/overview/fleet", registry: @overview.registry %>
|
|
29
|
-
<% end %>
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
<% if registry.any_dead? %>
|
|
2
|
-
<div class="fd-alert" role="alert">
|
|
3
|
-
<svg class="ic" width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M8 1.5 15 14H1L8 1.5z" stroke-linejoin="round"/><path d="M8 6v4M8 12.2v.2"/></svg>
|
|
4
|
-
<div>
|
|
5
|
-
<b><%= pluralize(registry.dead.size, "process") %> missed heartbeats for longer than
|
|
6
|
-
<%= fd_duration(SolidQueue.process_alive_threshold) %>.</b>
|
|
7
|
-
<% if registry.dead_claimed_count.positive? %>
|
|
8
|
-
<%= pluralize(registry.dead_claimed_count, "claimed execution") %> will be released and
|
|
9
|
-
marked failed when they are pruned.
|
|
10
|
-
<% else %>
|
|
11
|
-
They hold no claimed executions.
|
|
12
|
-
<% end %>
|
|
13
|
-
</div>
|
|
14
|
-
<div class="right">
|
|
15
|
-
<% if registry.dead_claimed_count.positive? %>
|
|
16
|
-
<%= link_to "Inspect claimed", jobs_path(state: :in_progress), class: "fd-btn sm" %>
|
|
17
|
-
<% end %>
|
|
18
|
-
</div>
|
|
19
|
-
</div>
|
|
20
|
-
<% end %>
|
|
21
|
-
|
|
22
|
-
<div class="fd-card">
|
|
23
|
-
<div class="fd-card-hd">
|
|
24
|
-
<h3>Processes</h3>
|
|
25
|
-
<span class="sub">grouped by supervisor · heartbeat threshold <%= fd_duration(SolidQueue.process_alive_threshold) %></span>
|
|
26
|
-
</div>
|
|
27
|
-
<div class="fd-scroll-x">
|
|
28
|
-
<table class="fd-data">
|
|
29
|
-
<thead>
|
|
30
|
-
<tr>
|
|
31
|
-
<th>Kind</th>
|
|
32
|
-
<th>Host</th>
|
|
33
|
-
<th class="num">PID</th>
|
|
34
|
-
<th>Configuration</th>
|
|
35
|
-
<th class="num">Claimed</th>
|
|
36
|
-
<th>Heartbeat</th>
|
|
37
|
-
<th style="width:90px"></th>
|
|
38
|
-
</tr>
|
|
39
|
-
</thead>
|
|
40
|
-
<tbody>
|
|
41
|
-
<% if registry.nodes.empty? %>
|
|
42
|
-
<tr><td colspan="7"><div class="fd-empty">No Solid Queue processes are registered.</div></td></tr>
|
|
43
|
-
<% else %>
|
|
44
|
-
<% registry.tree.each do |root| %>
|
|
45
|
-
<%= render "flightdeck/processes/row", node: root, child: false %>
|
|
46
|
-
<% root.children.each do |child| %>
|
|
47
|
-
<%= render "flightdeck/processes/row", node: child, child: true %>
|
|
48
|
-
<% end %>
|
|
49
|
-
<% end %>
|
|
50
|
-
<% end %>
|
|
51
|
-
</tbody>
|
|
52
|
-
</table>
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
<tr id="<%= dom_id_for_process(node.id) %>" class="<%= "fd-row-danger" if node.dead? %>">
|
|
2
|
-
<td class="cls<%= " fd-indent" if child %>">
|
|
3
|
-
<%= "↳ " if child %><%= node.kind %>
|
|
4
|
-
</td>
|
|
5
|
-
<td class="dim fd-mono" style="font-size:12px"><%= node.hostname.presence || "—" %></td>
|
|
6
|
-
<td class="num"><%= node.pid %></td>
|
|
7
|
-
<td class="dim"><%= node.config_summary.presence || "—" %></td>
|
|
8
|
-
<td class="num">
|
|
9
|
-
<% if node.claims_executions? %>
|
|
10
|
-
<%= link_to number_with_delimiter(node.claimed_count), jobs_path(state: :in_progress) %>
|
|
11
|
-
<% else %>
|
|
12
|
-
—
|
|
13
|
-
<% end %>
|
|
14
|
-
</td>
|
|
15
|
-
<td>
|
|
16
|
-
<span class="fd-hb">
|
|
17
|
-
<span class="fd-led <%= node.freshness %>"></span>
|
|
18
|
-
<%= fd_ago(node.last_heartbeat_at) %>
|
|
19
|
-
</span>
|
|
20
|
-
</td>
|
|
21
|
-
<td class="num">
|
|
22
|
-
<% if node.prunable? %>
|
|
23
|
-
<%= button_to "Prune", prune_process_path(node.id), class: "fd-btn sm danger",
|
|
24
|
-
form_class: "fd-inline-form",
|
|
25
|
-
data: { turbo_confirm: "Prune #{node.kind} #{node.name}? Its claimed jobs will be marked failed." } %>
|
|
26
|
-
<% end %>
|
|
27
|
-
</td>
|
|
28
|
-
</tr>
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
<% if stats.rows.empty? %>
|
|
2
|
-
<div class="fd-card"><div class="fd-empty">No queues yet. They appear as soon as jobs are enqueued.</div></div>
|
|
3
|
-
<% else %>
|
|
4
|
-
<div class="fd-queue-cards">
|
|
5
|
-
<% stats.rows.each do |queue| %>
|
|
6
|
-
<div class="fd-card fd-qcard<%= " paused-card" if queue.paused? %>" id="<%= dom_id_for_queue(queue.name) %>">
|
|
7
|
-
<div class="top">
|
|
8
|
-
<h3><%= queue.name %></h3>
|
|
9
|
-
<% if queue.paused? %>
|
|
10
|
-
<span class="fd-pill paused">PAUSED · <%= fd_duration(queue.paused_for) %></span>
|
|
11
|
-
<% else %>
|
|
12
|
-
<span class="fd-pill ready">ACTIVE</span>
|
|
13
|
-
<% end %>
|
|
14
|
-
<div class="right">
|
|
15
|
-
<% if queue.paused? %>
|
|
16
|
-
<%= button_to "▶ Resume", resume_queues_path(name: queue.name),
|
|
17
|
-
class: "fd-btn sm primary", form_class: "fd-inline-form" %>
|
|
18
|
-
<% else %>
|
|
19
|
-
<%= button_to "⏸ Pause", pause_queues_path(name: queue.name),
|
|
20
|
-
class: "fd-btn sm", form_class: "fd-inline-form",
|
|
21
|
-
data: { turbo_confirm: "Pause #{queue.name}? Workers will stop picking up its jobs until you resume it." } %>
|
|
22
|
-
<% end %>
|
|
23
|
-
</div>
|
|
24
|
-
</div>
|
|
25
|
-
|
|
26
|
-
<div class="stats">
|
|
27
|
-
<div>
|
|
28
|
-
<div class="k">Depth</div>
|
|
29
|
-
<div class="v"><%= number_with_delimiter(queue.depth) %></div>
|
|
30
|
-
</div>
|
|
31
|
-
<div>
|
|
32
|
-
<div class="k">Latency</div>
|
|
33
|
-
<div class="v"><%= queue.latency ? fd_duration(queue.latency) : "—" %></div>
|
|
34
|
-
</div>
|
|
35
|
-
<div>
|
|
36
|
-
<div class="k">Rate · 1h</div>
|
|
37
|
-
<div class="v"><%= number_with_delimiter(queue.rate_per_hour) %><small>/h</small></div>
|
|
38
|
-
</div>
|
|
39
|
-
</div>
|
|
40
|
-
|
|
41
|
-
<%= render "flightdeck/metrics/sparkline",
|
|
42
|
-
sparkline: Flightdeck::Metrics::Sparkline.new(sparklines[queue.name] || []) %>
|
|
43
|
-
</div>
|
|
44
|
-
<% end %>
|
|
45
|
-
</div>
|
|
46
|
-
<% end %>
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
<div class="fd-card">
|
|
2
|
-
<div class="fd-card-hd">
|
|
3
|
-
<h3>Recurring tasks</h3>
|
|
4
|
-
<span class="sub"><%= pluralize(catalog.rows.size, "task") %> registered</span>
|
|
5
|
-
</div>
|
|
6
|
-
<div class="fd-scroll-x">
|
|
7
|
-
<table class="fd-data">
|
|
8
|
-
<thead>
|
|
9
|
-
<tr>
|
|
10
|
-
<th>Key</th>
|
|
11
|
-
<th>Job</th>
|
|
12
|
-
<th>Schedule</th>
|
|
13
|
-
<th class="num">Last run</th>
|
|
14
|
-
<th class="num">Next run</th>
|
|
15
|
-
<th>Status</th>
|
|
16
|
-
<th style="width:110px"></th>
|
|
17
|
-
</tr>
|
|
18
|
-
</thead>
|
|
19
|
-
<tbody>
|
|
20
|
-
<% if catalog.rows.empty? %>
|
|
21
|
-
<tr><td colspan="7"><div class="fd-empty">No recurring tasks are configured.</div></td></tr>
|
|
22
|
-
<% else %>
|
|
23
|
-
<% catalog.rows.each do |row| %>
|
|
24
|
-
<tr id="<%= dom_id_for_recurring_task(row.id) %>">
|
|
25
|
-
<td class="cls"><%= row.key %></td>
|
|
26
|
-
<td class="dim"><%= row.job_class %></td>
|
|
27
|
-
<td class="fd-cron">
|
|
28
|
-
<%= row.schedule %>
|
|
29
|
-
<% if row.human_schedule %><small><%= row.human_schedule %></small><% end %>
|
|
30
|
-
</td>
|
|
31
|
-
<td class="num dim">
|
|
32
|
-
<%= row.ever_run? ? fd_ago(row.last_run_at) : "never" %>
|
|
33
|
-
</td>
|
|
34
|
-
<td class="num">
|
|
35
|
-
<% if row.next_run_at %>
|
|
36
|
-
<span title="<%= fd_full_time(row.next_run_at) %>">in <%= fd_duration(row.next_run_in) %></span>
|
|
37
|
-
<% else %>
|
|
38
|
-
—
|
|
39
|
-
<% end %>
|
|
40
|
-
</td>
|
|
41
|
-
<td><%= fd_recurring_status_pill(row.last_status) %></td>
|
|
42
|
-
<td class="num">
|
|
43
|
-
<%= button_to "▶ Run now", run_recurring_task_path(row.id),
|
|
44
|
-
class: "fd-btn sm", form_class: "fd-inline-form",
|
|
45
|
-
data: { turbo_confirm: "Enqueue #{row.key} now?" } %>
|
|
46
|
-
</td>
|
|
47
|
-
</tr>
|
|
48
|
-
<% end %>
|
|
49
|
-
<% end %>
|
|
50
|
-
</tbody>
|
|
51
|
-
</table>
|
|
52
|
-
</div>
|
|
53
|
-
</div>
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
<div class="<%= fd_toast_level_class(toast[:level]) %>"
|
|
2
|
-
role="status"
|
|
3
|
-
data-controller="toast"
|
|
4
|
-
data-toast-timeout-value="<%= toast[:continuable] ? 12_000 : 6_000 %>">
|
|
5
|
-
<span><%= toast[:message] %></span>
|
|
6
|
-
<button type="button" class="fd-toast-close" data-action="toast#dismiss" aria-label="Dismiss">✕</button>
|
|
7
|
-
</div>
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
<turbo-stream action="append" target="fd-toasts">
|
|
2
|
-
<template><%= render partial: "flightdeck/shared/toast", formats: [ :html ], locals: { toast: @toast } %></template>
|
|
3
|
-
</turbo-stream>
|
|
4
|
-
|
|
5
|
-
<%# Re-render the frame the action was launched from, so the same round trip
|
|
6
|
-
that carries the toast also carries settled rows and counts. A page that
|
|
7
|
-
does not have the frame (the job detail page, say) simply ignores this. %>
|
|
8
|
-
<turbo-stream action="replace" target="<%= @frame[:id] %>">
|
|
9
|
-
<template>
|
|
10
|
-
<%= fd_refresh_frame @frame[:id], url: @frame[:url], target: @frame.fetch(:target, "_top") do %>
|
|
11
|
-
<%= render partial: @frame[:partial], formats: [ :html ], locals: @frame[:locals] %>
|
|
12
|
-
<% end %>
|
|
13
|
-
</template>
|
|
14
|
-
</turbo-stream>
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
-
<title><%= content_for?(:title) ? yield(:title) : "Flightdeck" %></title>
|
|
7
|
-
<meta name="turbo-root" content="<%= root_path %>">
|
|
8
|
-
<%= csrf_meta_tags %>
|
|
9
|
-
<% if (css = flightdeck_asset_path("flightdeck.css")) %>
|
|
10
|
-
<link rel="stylesheet" href="<%= css %>">
|
|
11
|
-
<% end %>
|
|
12
|
-
<% if (js = flightdeck_asset_path("flightdeck.js")) %>
|
|
13
|
-
<script src="<%= js %>" defer></script>
|
|
14
|
-
<% end %>
|
|
15
|
-
</head>
|
|
16
|
-
<body data-controller="theme">
|
|
17
|
-
<div class="fd-app">
|
|
18
|
-
<aside class="fd-side">
|
|
19
|
-
<div class="fd-brand">
|
|
20
|
-
<%= flightdeck_brand_svg %>
|
|
21
|
-
<span class="fd-brand-word">FLIGHT<em>DECK</em></span>
|
|
22
|
-
</div>
|
|
23
|
-
|
|
24
|
-
<nav class="fd-nav">
|
|
25
|
-
<%= link_to root_path, class: "fd-nav-link#{" on" if current_page?(root_path)}" do %>
|
|
26
|
-
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" stroke="currentColor" stroke-width="1.4"><path d="M1.5 13.5v-5h3v5m1.5 0v-9h3v9m1.5 0v-12h3v12" stroke-linejoin="round"/></svg>
|
|
27
|
-
Overview
|
|
28
|
-
<% end %>
|
|
29
|
-
|
|
30
|
-
<span class="fd-nav-section">Jobs</span>
|
|
31
|
-
|
|
32
|
-
<%= link_to jobs_path, class: "fd-nav-link#{" on" if fd_nav_active?(:all)}" do %>
|
|
33
|
-
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" stroke="currentColor" stroke-width="1.4"><rect x="1.5" y="2.5" width="12" height="10" rx="1.5"/><path d="M4.5 6h6M4.5 9h4"/></svg>
|
|
34
|
-
All jobs <span class="fd-nav-count"><%= fd_nav_count(:all) %></span>
|
|
35
|
-
<% end %>
|
|
36
|
-
|
|
37
|
-
<%= link_to jobs_path(state: :failed), class: "fd-nav-link#{" on" if fd_nav_active?(:failed)}" do %>
|
|
38
|
-
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" stroke="currentColor" stroke-width="1.4"><circle cx="7.5" cy="7.5" r="6"/><path d="M7.5 4.5v3.5M7.5 10.4v.2"/></svg>
|
|
39
|
-
Failed <span class="fd-nav-count"><%= fd_nav_count(:failed) %></span>
|
|
40
|
-
<% end %>
|
|
41
|
-
|
|
42
|
-
<span class="fd-nav-section">Infrastructure</span>
|
|
43
|
-
|
|
44
|
-
<%= link_to queues_path, class: "fd-nav-link#{" on" if controller_name == "queues"}" do %>
|
|
45
|
-
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" stroke="currentColor" stroke-width="1.4"><path d="M2 4h11M2 7.5h11M2 11h7"/></svg>
|
|
46
|
-
Queues <span class="fd-nav-count"><%= fd_nav_queue_count %></span>
|
|
47
|
-
<% end %>
|
|
48
|
-
|
|
49
|
-
<%= link_to processes_path, class: "fd-nav-link#{" on" if controller_name == "processes"}" do %>
|
|
50
|
-
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" stroke="currentColor" stroke-width="1.4"><rect x="2" y="2" width="11" height="7" rx="1.5"/><path d="M5 13h5M7.5 9v4"/></svg>
|
|
51
|
-
Processes <span class="fd-nav-count <%= "alert" if fd_nav_any_dead_processes? %>"><%= fd_nav_process_count %></span>
|
|
52
|
-
<% end %>
|
|
53
|
-
|
|
54
|
-
<%= link_to recurring_tasks_path, class: "fd-nav-link#{" on" if controller_name == "recurring_tasks"}" do %>
|
|
55
|
-
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" stroke="currentColor" stroke-width="1.4"><circle cx="7.5" cy="7.5" r="6"/><path d="M7.5 4v3.5l2.5 1.5"/></svg>
|
|
56
|
-
Recurring <span class="fd-nav-count"><%= fd_nav_recurring_count %></span>
|
|
57
|
-
<% end %>
|
|
58
|
-
</nav>
|
|
59
|
-
|
|
60
|
-
<div class="fd-side-foot">
|
|
61
|
-
<b>flightdeck</b><br>
|
|
62
|
-
v<%= Flightdeck::VERSION %>
|
|
63
|
-
</div>
|
|
64
|
-
</aside>
|
|
65
|
-
|
|
66
|
-
<div class="fd-main">
|
|
67
|
-
<div class="fd-topbar">
|
|
68
|
-
<h2><%= content_for?(:page_title) ? yield(:page_title) : "Overview" %></h2>
|
|
69
|
-
<div class="fd-topbar-right">
|
|
70
|
-
<span class="fd-clock"
|
|
71
|
-
data-controller="clock"
|
|
72
|
-
data-clock-offset-value="<%= fd_zone_offset_seconds %>"
|
|
73
|
-
data-clock-label-value="<%= fd_zone_label %>"><%= fd_clock_now %></span>
|
|
74
|
-
|
|
75
|
-
<button class="fd-live" type="button" aria-pressed="true"
|
|
76
|
-
data-controller="live"
|
|
77
|
-
data-live-interval-value="<%= fd_poll_ms %>"
|
|
78
|
-
data-action="live#toggle">
|
|
79
|
-
<span class="fd-dot"></span>
|
|
80
|
-
<span data-live-target="label">LIVE · <%= fd_poll_seconds %>s</span>
|
|
81
|
-
</button>
|
|
82
|
-
|
|
83
|
-
<%# Which icon shows is decided by theme tokens, so it is correct on
|
|
84
|
-
first paint without waiting for JavaScript. The controller
|
|
85
|
-
refines the label to name the action once it connects. %>
|
|
86
|
-
<button class="fd-theme-toggle" type="button"
|
|
87
|
-
data-action="theme#toggle" data-theme-target="button"
|
|
88
|
-
aria-label="Switch theme" title="Switch theme">
|
|
89
|
-
<svg class="fd-icon-sun" width="15" height="15" viewBox="0 0 16 16" fill="none"
|
|
90
|
-
stroke="currentColor" stroke-width="1.4" stroke-linecap="round" aria-hidden="true">
|
|
91
|
-
<circle cx="8" cy="8" r="3.1"/>
|
|
92
|
-
<path d="M8 1.2v1.6M8 13.2v1.6M14.8 8h-1.6M2.8 8H1.2M12.8 3.2l-1.1 1.1M4.3 11.7l-1.1 1.1M12.8 12.8l-1.1-1.1M4.3 4.3 3.2 3.2"/>
|
|
93
|
-
</svg>
|
|
94
|
-
<svg class="fd-icon-moon" width="15" height="15" viewBox="0 0 16 16" fill="none"
|
|
95
|
-
stroke="currentColor" stroke-width="1.4" stroke-linejoin="round" aria-hidden="true">
|
|
96
|
-
<path d="M13.4 9.8A5.9 5.9 0 0 1 6.2 2.6a5.9 5.9 0 1 0 7.2 7.2z"/>
|
|
97
|
-
</svg>
|
|
98
|
-
</button>
|
|
99
|
-
</div>
|
|
100
|
-
</div>
|
|
101
|
-
|
|
102
|
-
<main class="fd-content">
|
|
103
|
-
<%= yield %>
|
|
104
|
-
</main>
|
|
105
|
-
</div>
|
|
106
|
-
</div>
|
|
107
|
-
|
|
108
|
-
<div id="fd-toasts" class="fd-toasts" aria-live="polite" aria-atomic="false"></div>
|
|
109
|
-
</body>
|
|
110
|
-
</html>
|
data/config/routes.rb
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
Flightdeck::Engine.routes.draw do
|
|
4
|
-
root to: "overview#index"
|
|
5
|
-
|
|
6
|
-
resources :jobs, only: %i[index show] do
|
|
7
|
-
member do
|
|
8
|
-
post :retry, to: "jobs/retries#create"
|
|
9
|
-
post :discard, to: "jobs/discards#create"
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
collection do
|
|
13
|
-
post :retry, to: "jobs/retries#create", as: :bulk_retry
|
|
14
|
-
post :discard, to: "jobs/discards#create", as: :bulk_discard
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# Queue names are arbitrary strings (dots, slashes, colons all legal), so the
|
|
19
|
-
# name travels as a parameter rather than as a path segment.
|
|
20
|
-
resources :queues, only: :index do
|
|
21
|
-
collection do
|
|
22
|
-
post :pause
|
|
23
|
-
post :resume
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
resources :processes, only: :index do
|
|
28
|
-
member { post :prune }
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
resources :recurring_tasks, only: :index do
|
|
32
|
-
member { post :run }
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
get "assets/:name",
|
|
36
|
-
to: "assets#show",
|
|
37
|
-
as: :asset_file,
|
|
38
|
-
format: false,
|
|
39
|
-
constraints: { name: /flightdeck-[0-9a-f]{12}\.(?:css|js)/ }
|
|
40
|
-
end
|