solid_queue_web 0.8.0 → 1.0.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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +106 -17
  3. data/Rakefile +3 -1
  4. data/app/assets/stylesheets/solid_queue_web/_04_table.css +8 -1
  5. data/app/assets/stylesheets/solid_queue_web/_05_badges.css +1 -0
  6. data/app/assets/stylesheets/solid_queue_web/_07_forms.css +17 -0
  7. data/app/assets/stylesheets/solid_queue_web/_11_throughput.css +30 -1
  8. data/app/controllers/solid_queue_web/application_controller.rb +19 -1
  9. data/app/controllers/solid_queue_web/blocked_jobs_controller.rb +11 -0
  10. data/app/controllers/solid_queue_web/dashboard_controller.rb +2 -38
  11. data/app/controllers/solid_queue_web/jobs_controller.rb +16 -27
  12. data/app/controllers/solid_queue_web/metrics_controller.rb +7 -0
  13. data/app/controllers/solid_queue_web/performance_controller.rb +12 -0
  14. data/app/controllers/solid_queue_web/queues/jobs_controller.rb +15 -19
  15. data/app/controllers/solid_queue_web/queues/pauses_controller.rb +21 -0
  16. data/app/controllers/solid_queue_web/queues_controller.rb +5 -31
  17. data/app/controllers/solid_queue_web/recurring_tasks/runs_controller.rb +18 -0
  18. data/app/controllers/solid_queue_web/retry_failed_jobs_controller.rb +23 -2
  19. data/app/controllers/solid_queue_web/scheduled_jobs_controller.rb +54 -0
  20. data/app/models/solid_queue_web/job.rb +17 -1
  21. data/app/services/solid_queue_web/alert_webhook.rb +58 -0
  22. data/app/services/solid_queue_web/dashboard_stats.rb +47 -0
  23. data/app/services/solid_queue_web/job_performance_stats.rb +38 -0
  24. data/app/services/solid_queue_web/metrics_payload.rb +66 -0
  25. data/app/services/solid_queue_web/queue_stats.rb +52 -0
  26. data/app/views/layouts/solid_queue_web/application.html.erb +1 -0
  27. data/app/views/solid_queue_web/dashboard/index.html.erb +68 -24
  28. data/app/views/solid_queue_web/failed_jobs/index.html.erb +11 -1
  29. data/app/views/solid_queue_web/history/index.html.erb +1 -1
  30. data/app/views/solid_queue_web/jobs/index.html.erb +57 -15
  31. data/app/views/solid_queue_web/performance/index.html.erb +50 -0
  32. data/app/views/solid_queue_web/queues/index.html.erb +19 -2
  33. data/app/views/solid_queue_web/queues/jobs/index.html.erb +1 -1
  34. data/app/views/solid_queue_web/recurring_tasks/index.html.erb +7 -0
  35. data/app/views/solid_queue_web/scheduled_jobs/update.turbo_stream.erb +9 -0
  36. data/app/views/solid_queue_web/search/index.html.erb +1 -1
  37. data/config/routes.rb +16 -10
  38. data/lib/solid_queue_web/version.rb +1 -1
  39. data/lib/solid_queue_web.rb +23 -1
  40. metadata +14 -1
@@ -5,22 +5,29 @@
5
5
 
6
6
  <div class="sqd-page-header">
7
7
  <div class="sqd-filters">
8
- <%= link_to "Ready", jobs_path(status: "ready", q: @search, period: @period), class: @status == "ready" ? "active" : "" %>
9
- <%= link_to "Scheduled", jobs_path(status: "scheduled", q: @search, period: @period), class: @status == "scheduled" ? "active" : "" %>
10
- <%= link_to "Running", jobs_path(status: "claimed", q: @search, period: @period), class: @status == "claimed" ? "active" : "" %>
11
- <%= link_to "Blocked", jobs_path(status: "blocked", q: @search, period: @period), class: @status == "blocked" ? "active" : "" %>
12
- <%= link_to "Failed", jobs_path(status: "failed", q: @search, period: @period), class: @status == "failed" ? "active" : "" %>
8
+ <%= link_to "Ready", jobs_path(status: "ready", q: @search, period: @period, priority: @priority), class: @status == "ready" ? "active" : "" %>
9
+ <%= link_to "Scheduled", jobs_path(status: "scheduled", q: @search, period: @period, priority: @priority), class: @status == "scheduled" ? "active" : "" %>
10
+ <%= link_to "Running", jobs_path(status: "claimed", q: @search, period: @period, priority: @priority), class: @status == "claimed" ? "active" : "" %>
11
+ <%= link_to "Blocked", jobs_path(status: "blocked", q: @search, period: @period, priority: @priority), class: @status == "blocked" ? "active" : "" %>
12
+ <%= link_to "Failed", jobs_path(status: "failed", q: @search, period: @period, priority: @priority), class: @status == "failed" ? "active" : "" %>
13
13
  </div>
14
14
  <% if @jobs.any? %>
15
15
  <div class="sqd-actions">
16
16
  <%= link_to "Export CSV", jobs_path(format: :csv, status: @status, q: @search, period: @period),
17
17
  class: "sqd-btn sqd-btn--muted", data: { turbo: false } %>
18
+ <% if @status == "scheduled" %>
19
+ <%= button_to "Run All Now", run_all_now_scheduled_jobs_path,
20
+ method: :post,
21
+ params: { period: @period },
22
+ class: "sqd-btn sqd-btn--primary",
23
+ data: { confirm: "Run all #{@pagy.count} scheduled jobs immediately?" } %>
24
+ <% end %>
18
25
  <% if discardable %>
19
26
  <%= button_to "Discard All", discard_all_jobs_path,
20
27
  method: :post,
21
28
  params: { status: @status, period: @period },
22
29
  class: "sqd-btn sqd-btn--danger",
23
- data: { confirm: "Discard all #{@jobs.size} #{@status} jobs? This cannot be undone." } %>
30
+ data: { confirm: "Discard all #{@pagy.count} #{@status} jobs? This cannot be undone." } %>
24
31
  <% end %>
25
32
  </div>
26
33
  <% end %>
@@ -32,14 +39,23 @@
32
39
  <input class="sqd-search__input" type="search" name="q" value="<%= @search %>"
33
40
  placeholder="Filter by job class…" autocomplete="off" aria-label="Filter by job class"
34
41
  data-action="input->search#filter">
35
- <% if @search.present? %>
42
+ <% if @priority_options.size > 1 %>
43
+ <select name="priority" class="sqd-select" aria-label="Filter by priority"
44
+ onchange="this.form.submit()">
45
+ <option value="" <%= @priority.nil? ? "selected" : "" %>>All priorities</option>
46
+ <% @priority_options.each do |p| %>
47
+ <option value="<%= p %>" <%= @priority.to_s == p.to_s ? "selected" : "" %>>Priority <%= p %></option>
48
+ <% end %>
49
+ </select>
50
+ <% end %>
51
+ <% if @search.present? || @priority.present? %>
36
52
  <%= link_to "Clear", jobs_path(status: @status, period: @period), class: "sqd-btn sqd-btn--muted" %>
37
53
  <% end %>
38
54
  <div class="sqd-period-filter" role="group" aria-label="Time period">
39
- <%= link_to "All", jobs_path(status: @status, q: @search), class: @period.nil? ? "active" : "", aria: { current: @period.nil? ? "true" : nil }, aria_label: "All time" %>
40
- <%= link_to "1h", jobs_path(status: @status, q: @search, period: "1h"), class: @period == "1h" ? "active" : "", aria: { current: @period == "1h" ? "true" : nil }, aria_label: "Last 1 hour" %>
41
- <%= link_to "24h", jobs_path(status: @status, q: @search, period: "24h"), class: @period == "24h" ? "active" : "", aria: { current: @period == "24h" ? "true" : nil }, aria_label: "Last 24 hours" %>
42
- <%= link_to "7d", jobs_path(status: @status, q: @search, period: "7d"), class: @period == "7d" ? "active" : "", aria: { current: @period == "7d" ? "true" : nil }, aria_label: "Last 7 days" %>
55
+ <%= link_to "All", jobs_path(status: @status, q: @search, priority: @priority), class: @period.nil? ? "active" : "", aria: { current: @period.nil? ? "true" : nil }, aria_label: "All time" %>
56
+ <%= link_to "1h", jobs_path(status: @status, q: @search, priority: @priority, period: "1h"), class: @period == "1h" ? "active" : "", aria: { current: @period == "1h" ? "true" : nil }, aria_label: "Last 1 hour" %>
57
+ <%= link_to "24h", jobs_path(status: @status, q: @search, priority: @priority, period: "24h"), class: @period == "24h" ? "active" : "", aria: { current: @period == "24h" ? "true" : nil }, aria_label: "Last 24 hours" %>
58
+ <%= link_to "7d", jobs_path(status: @status, q: @search, priority: @priority, period: "7d"), class: @period == "7d" ? "active" : "", aria: { current: @period == "7d" ? "true" : nil }, aria_label: "Last 7 days" %>
43
59
  </div>
44
60
  </form>
45
61
 
@@ -87,18 +103,31 @@
87
103
  </td>
88
104
  <td>
89
105
  <span class="sqd-badge sqd-badge--<%= @status %>"><%= @status %></span>
90
- <%= link_to job.class_name, job_path(job), style: "margin-left: 0.5rem;", data: { turbo_frame: "_top" } %>
106
+ <%= link_to job.class_name, job_path(job), class: "sqd-table-link", style: "margin-left: 0.5rem;", data: { turbo_frame: "_top" } %>
91
107
  </td>
92
108
  <td>
93
109
  <%= link_to job.queue_name, queue_jobs_path(queue_name: job.queue_name, status: @status),
94
110
  class: "sqd-mono", style: "color: inherit;" %>
95
111
  </td>
96
112
  <td><%= job.priority %></td>
97
- <td class="sqd-mono">
113
+ <td id="scheduled_at_<%= execution.id %>" class="sqd-mono">
98
114
  <%= job.scheduled_at ? job.scheduled_at.strftime("%Y-%m-%d %H:%M:%S") : "—" %>
99
115
  </td>
100
116
  <td class="sqd-mono"><%= job.created_at.strftime("%Y-%m-%d %H:%M:%S") %></td>
101
117
  <td class="sqd-row-actions">
118
+ <% if @status == "scheduled" %>
119
+ <%= button_to "Run Now", scheduled_job_path(execution),
120
+ method: :patch,
121
+ params: { offset: "now", period: @period },
122
+ class: "sqd-btn sqd-btn--primary sqd-btn--sm",
123
+ data: { confirm: "Run this job immediately?" } %>
124
+ <% %w[1h 24h 7d].each do |offset| %>
125
+ <%= button_to "+#{offset}", scheduled_job_path(execution),
126
+ method: :patch,
127
+ params: { offset: offset, period: @period },
128
+ class: "sqd-btn sqd-btn--muted sqd-btn--sm" %>
129
+ <% end %>
130
+ <% end %>
102
131
  <%= button_to "Discard", job_path(execution),
103
132
  method: :delete,
104
133
  params: { status: @status, period: @period },
@@ -116,6 +145,7 @@
116
145
  <% if @jobs.empty? %>
117
146
  <div class="sqd-empty">No <%= @status %> jobs.</div>
118
147
  <% else %>
148
+ <% slow_threshold = @status == "claimed" ? SolidQueueWeb.slow_job_threshold : nil %>
119
149
  <table>
120
150
  <thead>
121
151
  <tr>
@@ -124,15 +154,22 @@
124
154
  <th scope="col">Priority</th>
125
155
  <th scope="col">Scheduled At</th>
126
156
  <th scope="col">Enqueued At</th>
157
+ <% if @status == "claimed" %>
158
+ <th scope="col">Running For</th>
159
+ <% end %>
127
160
  </tr>
128
161
  </thead>
129
162
  <tbody>
130
163
  <% @jobs.each do |execution| %>
131
164
  <% job = execution.job %>
132
- <tr id="execution_<%= execution.id %>">
165
+ <% slow = slow_threshold && execution.created_at <= slow_threshold.ago %>
166
+ <tr id="execution_<%= execution.id %>"<%= slow ? ' class="sqd-row--slow"'.html_safe : "" %>>
133
167
  <td>
134
168
  <span class="sqd-badge sqd-badge--<%= @status %>"><%= @status %></span>
135
- <%= link_to job.class_name, job_path(job), style: "margin-left: 0.5rem;", data: { turbo_frame: "_top" } %>
169
+ <% if slow %>
170
+ <span class="sqd-badge sqd-badge--slow">slow</span>
171
+ <% end %>
172
+ <%= link_to job.class_name, job_path(job), class: "sqd-table-link", style: "margin-left: 0.5rem;", data: { turbo_frame: "_top" } %>
136
173
  </td>
137
174
  <td>
138
175
  <%= link_to job.queue_name, queue_jobs_path(queue_name: job.queue_name, status: @status),
@@ -143,6 +180,11 @@
143
180
  <%= job.scheduled_at ? job.scheduled_at.strftime("%Y-%m-%d %H:%M:%S") : "—" %>
144
181
  </td>
145
182
  <td class="sqd-mono"><%= job.created_at.strftime("%Y-%m-%d %H:%M:%S") %></td>
183
+ <% if @status == "claimed" %>
184
+ <td class="sqd-mono<%= slow ? " sqd-slow-duration" : "" %>">
185
+ <%= time_ago_in_words(execution.created_at) %>
186
+ </td>
187
+ <% end %>
146
188
  </tr>
147
189
  <% end %>
148
190
  </tbody>
@@ -0,0 +1,50 @@
1
+ <div class="sqd-page-header">
2
+ <h1 class="sqd-page-title">Performance</h1>
3
+ </div>
4
+
5
+ <form class="sqd-search" action="<%= performance_path %>" method="get">
6
+ <div class="sqd-period-filter" role="group" aria-label="Time period">
7
+ <%= link_to "All", performance_path, class: @period.nil? ? "active" : "", aria: { current: @period.nil? ? "true" : nil } %>
8
+ <%= link_to "1h", performance_path(period: "1h"), class: @period == "1h" ? "active" : "", aria: { current: @period == "1h" ? "true" : nil } %>
9
+ <%= link_to "24h", performance_path(period: "24h"), class: @period == "24h" ? "active" : "", aria: { current: @period == "24h" ? "true" : nil } %>
10
+ <%= link_to "7d", performance_path(period: "7d"), class: @period == "7d" ? "active" : "", aria: { current: @period == "7d" ? "true" : nil } %>
11
+ </div>
12
+ </form>
13
+
14
+ <% if @rows.any? %>
15
+ <div class="sqd-card" style="margin-top: 1rem;">
16
+ <table>
17
+ <thead>
18
+ <tr>
19
+ <th scope="col">Job Class</th>
20
+ <th scope="col" style="text-align: right;">Runs</th>
21
+ <th scope="col" style="text-align: right;">Avg</th>
22
+ <th scope="col" style="text-align: right;">p50</th>
23
+ <th scope="col" style="text-align: right;">p95</th>
24
+ <th scope="col" style="text-align: right;">Min</th>
25
+ <th scope="col" style="text-align: right;">Max</th>
26
+ </tr>
27
+ </thead>
28
+ <tbody>
29
+ <% @rows.each do |row| %>
30
+ <tr>
31
+ <td>
32
+ <%= link_to row.class_name, history_path(q: row.class_name, period: @period),
33
+ class: "sqd-table-link" %>
34
+ </td>
35
+ <td class="sqd-mono" style="text-align: right;"><%= row.count %></td>
36
+ <td class="sqd-mono" style="text-align: right;"><%= format_duration(row.avg) %></td>
37
+ <td class="sqd-mono" style="text-align: right;"><%= format_duration(row.p50) %></td>
38
+ <td class="sqd-mono" style="text-align: right;"><%= format_duration(row.p95) %></td>
39
+ <td class="sqd-mono" style="text-align: right;"><%= format_duration(row.min) %></td>
40
+ <td class="sqd-mono" style="text-align: right;"><%= format_duration(row.max) %></td>
41
+ </tr>
42
+ <% end %>
43
+ </tbody>
44
+ </table>
45
+ </div>
46
+ <% else %>
47
+ <div class="sqd-card" style="margin-top: 1rem;">
48
+ <div class="sqd-empty">No finished jobs found<%= " in the last #{@period}" if @period %>.</div>
49
+ </div>
50
+ <% end %>
@@ -12,6 +12,7 @@
12
12
  <th scope="col">Latency</th>
13
13
  <th scope="col">Done (24h)</th>
14
14
  <th scope="col">Failed (24h)</th>
15
+ <th scope="col">Failure Rate (12h)</th>
15
16
  <th scope="col">Status</th>
16
17
  <th scope="col"><span class="sqd-sr-only">Actions</span></th>
17
18
  </tr>
@@ -34,6 +35,22 @@
34
35
  </td>
35
36
  <td style="color: var(--success);"><%= @completed_24h[queue.name] || 0 %></td>
36
37
  <td style="color: <%= (@failed_24h[queue.name] || 0) > 0 ? "var(--danger)" : "inherit" %>;"><%= @failed_24h[queue.name] || 0 %></td>
38
+ <td>
39
+ <% sparkline = @failure_sparklines[queue.name] %>
40
+ <% if sparkline.any? %>
41
+ <div class="sqd-mini-sparkline" aria-label="Failure rate last 12 hours for <%= queue.name %>">
42
+ <% sparkline.each_with_index do |rate, i| %>
43
+ <% pct = rate || 0 %>
44
+ <% hour_label = (12 - i).hours.ago.strftime("%-I%p").downcase %>
45
+ <div class="sqd-mini-sparkline__bar sqd-mini-sparkline__bar--<%= rate ? "data" : "empty" %>"
46
+ style="height: <%= [pct, 2].max %>%"
47
+ title="<%= hour_label %>: <%= rate ? "#{rate}% failure rate" : "no data" %>"></div>
48
+ <% end %>
49
+ </div>
50
+ <% else %>
51
+ <span style="color: var(--muted)">—</span>
52
+ <% end %>
53
+ </td>
37
54
  <td>
38
55
  <% if queue.paused? %>
39
56
  <span class="sqd-badge sqd-badge--paused">Paused</span>
@@ -43,10 +60,10 @@
43
60
  </td>
44
61
  <td class="sqd-row-actions">
45
62
  <% if queue.paused? %>
46
- <%= button_to "Resume", resume_queue_path(queue.name), method: :post,
63
+ <%= button_to "Resume", queue_pause_path(queue.name), method: :delete,
47
64
  class: "sqd-btn sqd-btn--primary sqd-btn--sm" %>
48
65
  <% else %>
49
- <%= button_to "Pause", pause_queue_path(queue.name), method: :post,
66
+ <%= button_to "Pause", queue_pause_path(queue.name), method: :post,
50
67
  class: "sqd-btn sqd-btn--muted sqd-btn--sm",
51
68
  data: { confirm: "Pause queue \"#{queue.name}\"?" } %>
52
69
  <% end %>
@@ -60,7 +60,7 @@
60
60
  <tr id="execution_<%= execution.id %>">
61
61
  <td>
62
62
  <span class="sqd-badge sqd-badge--<%= @status %>"><%= @status %></span>
63
- <%= link_to job.class_name, job_path(job), style: "margin-left: 0.5rem;", data: { turbo_frame: "_top" } %>
63
+ <%= link_to job.class_name, job_path(job), class: "sqd-table-link", style: "margin-left: 0.5rem;", data: { turbo_frame: "_top" } %>
64
64
  </td>
65
65
  <td><%= job.priority %></td>
66
66
  <td class="sqd-mono">
@@ -14,6 +14,7 @@
14
14
  <th scope="col">Next Run</th>
15
15
  <th scope="col">Last Run</th>
16
16
  <th scope="col">Type</th>
17
+ <th scope="col"><span class="sqd-sr-only">Actions</span></th>
17
18
  </tr>
18
19
  </thead>
19
20
  <tbody>
@@ -60,6 +61,12 @@
60
61
  <span class="sqd-badge sqd-badge--dynamic">Dynamic</span>
61
62
  <% end %>
62
63
  </td>
64
+ <td class="sqd-row-actions">
65
+ <%= button_to "Run Now", recurring_task_run_path(task.key),
66
+ method: :post,
67
+ class: "sqd-btn sqd-btn--primary sqd-btn--sm",
68
+ data: { confirm: "Run \"#{task.key}\" immediately?" } %>
69
+ </td>
63
70
  </tr>
64
71
  <% end %>
65
72
  </tbody>
@@ -0,0 +1,9 @@
1
+ <% if @run_now %>
2
+ <%= turbo_stream.remove "execution_#{@execution.id}" %>
3
+ <% else %>
4
+ <%= turbo_stream.replace "scheduled_at_#{@execution.id}" do %>
5
+ <td id="scheduled_at_<%= @execution.id %>" class="sqd-mono">
6
+ <%= @execution.scheduled_at.strftime("%Y-%m-%d %H:%M:%S") %>
7
+ </td>
8
+ <% end %>
9
+ <% end %>
@@ -50,7 +50,7 @@
50
50
  <% data[:executions].each do |execution| %>
51
51
  <% job = execution.job %>
52
52
  <tr>
53
- <td><%= link_to job.class_name, job_path(job) %></td>
53
+ <td><%= link_to job.class_name, job_path(job), class: "sqd-table-link" %></td>
54
54
  <td class="sqd-mono"><%= job.queue_name %></td>
55
55
  <td class="sqd-mono"><%= job.created_at.strftime("%Y-%m-%d %H:%M:%S") %></td>
56
56
  </tr>
data/config/routes.rb CHANGED
@@ -1,27 +1,33 @@
1
1
  SolidQueueWeb::Engine.routes.draw do
2
2
  root to: "dashboard#index"
3
- post "retry_all_failed", to: "dashboard#retry_all_failed", as: :retry_all_failed
4
- post "discard_all_blocked", to: "dashboard#discard_all_blocked", as: :discard_all_blocked
3
+ resource :blocked_jobs, only: [:destroy]
5
4
 
6
- get "search", to: "search#index", as: :search
7
- get "history", to: "history#index", as: :history
5
+ get "metrics", to: "metrics#index", as: :metrics, defaults: { format: :json }
6
+ get "search", to: "search#index", as: :search
7
+ get "history", to: "history#index", as: :history
8
+ get "performance", to: "performance#index", as: :performance
8
9
 
9
- resources :recurring_tasks, only: [:index]
10
+ resources :recurring_tasks, only: [:index], param: :key do
11
+ resource :run, only: [:create], controller: "recurring_tasks/runs"
12
+ end
10
13
  resources :processes, only: [:index]
11
14
  resources :queues, only: [:index], param: :name do
12
- member do
13
- post :pause
14
- post :resume
15
- end
15
+ resource :pause, only: [:create, :destroy], controller: "queues/pauses"
16
16
  resources :jobs, path: "list", only: [:index, :destroy], controller: "queues/jobs" do
17
17
  collection do
18
- post :discard_all
18
+ post :discard_all, action: :destroy
19
19
  end
20
20
  end
21
21
  end
22
22
 
23
23
  # Singular selection resources must be defined before the member routes of their
24
24
  # parent resources, otherwise DELETE /list/selection matches /list/:id first.
25
+ resources :scheduled_jobs, only: [:update] do
26
+ collection do
27
+ post :run_all_now, action: :create
28
+ end
29
+ end
30
+
25
31
  resource :job_selection, path: "list/selection", only: [:destroy], controller: "jobs/selections"
26
32
  resources :jobs, path: "list", only: [:index, :show, :destroy] do
27
33
  collection do
@@ -1,3 +1,3 @@
1
1
  module SolidQueueWeb
2
- VERSION = "0.8.0"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -4,7 +4,9 @@ require "solid_queue_web/engine"
4
4
 
5
5
  module SolidQueueWeb
6
6
  class << self
7
- attr_writer :page_size, :dashboard_refresh_interval, :default_refresh_interval, :search_results_limit
7
+ attr_writer :page_size, :dashboard_refresh_interval, :default_refresh_interval, :search_results_limit,
8
+ :slow_job_threshold, :alert_webhook_url, :alert_failure_threshold, :alert_webhook_cooldown,
9
+ :connects_to
8
10
 
9
11
  def page_size
10
12
  @page_size || 25
@@ -22,6 +24,26 @@ module SolidQueueWeb
22
24
  @search_results_limit || 25
23
25
  end
24
26
 
27
+ def slow_job_threshold
28
+ @slow_job_threshold
29
+ end
30
+
31
+ def alert_webhook_url
32
+ @alert_webhook_url
33
+ end
34
+
35
+ def alert_failure_threshold
36
+ @alert_failure_threshold
37
+ end
38
+
39
+ def alert_webhook_cooldown
40
+ @alert_webhook_cooldown || 3600
41
+ end
42
+
43
+ def connects_to
44
+ @connects_to
45
+ end
46
+
25
47
  def configure
26
48
  yield self
27
49
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solid_queue_web
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chuck Smith
@@ -119,17 +119,23 @@ files:
119
119
  - app/assets/stylesheets/solid_queue_web/_12_dark_mode.css
120
120
  - app/assets/stylesheets/solid_queue_web/application.css
121
121
  - app/controllers/solid_queue_web/application_controller.rb
122
+ - app/controllers/solid_queue_web/blocked_jobs_controller.rb
122
123
  - app/controllers/solid_queue_web/dashboard_controller.rb
123
124
  - app/controllers/solid_queue_web/failed_jobs/selections_controller.rb
124
125
  - app/controllers/solid_queue_web/failed_jobs_controller.rb
125
126
  - app/controllers/solid_queue_web/history_controller.rb
126
127
  - app/controllers/solid_queue_web/jobs/selections_controller.rb
127
128
  - app/controllers/solid_queue_web/jobs_controller.rb
129
+ - app/controllers/solid_queue_web/metrics_controller.rb
130
+ - app/controllers/solid_queue_web/performance_controller.rb
128
131
  - app/controllers/solid_queue_web/processes_controller.rb
129
132
  - app/controllers/solid_queue_web/queues/jobs_controller.rb
133
+ - app/controllers/solid_queue_web/queues/pauses_controller.rb
130
134
  - app/controllers/solid_queue_web/queues_controller.rb
135
+ - app/controllers/solid_queue_web/recurring_tasks/runs_controller.rb
131
136
  - app/controllers/solid_queue_web/recurring_tasks_controller.rb
132
137
  - app/controllers/solid_queue_web/retry_failed_jobs_controller.rb
138
+ - app/controllers/solid_queue_web/scheduled_jobs_controller.rb
133
139
  - app/controllers/solid_queue_web/search_controller.rb
134
140
  - app/helpers/solid_queue_web/application_helper.rb
135
141
  - app/javascript/solid_queue_web/application.js
@@ -140,6 +146,11 @@ files:
140
146
  - app/jobs/solid_queue_web/application_job.rb
141
147
  - app/models/solid_queue_web/application_record.rb
142
148
  - app/models/solid_queue_web/job.rb
149
+ - app/services/solid_queue_web/alert_webhook.rb
150
+ - app/services/solid_queue_web/dashboard_stats.rb
151
+ - app/services/solid_queue_web/job_performance_stats.rb
152
+ - app/services/solid_queue_web/metrics_payload.rb
153
+ - app/services/solid_queue_web/queue_stats.rb
143
154
  - app/views/layouts/solid_queue_web/application.html.erb
144
155
  - app/views/solid_queue_web/dashboard/index.html.erb
145
156
  - app/views/solid_queue_web/failed_jobs/index.html.erb
@@ -147,11 +158,13 @@ files:
147
158
  - app/views/solid_queue_web/jobs/destroy.turbo_stream.erb
148
159
  - app/views/solid_queue_web/jobs/index.html.erb
149
160
  - app/views/solid_queue_web/jobs/show.html.erb
161
+ - app/views/solid_queue_web/performance/index.html.erb
150
162
  - app/views/solid_queue_web/processes/index.html.erb
151
163
  - app/views/solid_queue_web/queues/index.html.erb
152
164
  - app/views/solid_queue_web/queues/jobs/destroy.turbo_stream.erb
153
165
  - app/views/solid_queue_web/queues/jobs/index.html.erb
154
166
  - app/views/solid_queue_web/recurring_tasks/index.html.erb
167
+ - app/views/solid_queue_web/scheduled_jobs/update.turbo_stream.erb
155
168
  - app/views/solid_queue_web/search/index.html.erb
156
169
  - config/importmap.rb
157
170
  - config/routes.rb