solid_stack_web 0.2.0 → 0.4.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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +104 -22
  3. data/app/assets/stylesheets/solid_stack_web/_02_layout.css +8 -0
  4. data/app/assets/stylesheets/solid_stack_web/_04_table.css +4 -0
  5. data/app/assets/stylesheets/solid_stack_web/_07_dashboard.css +64 -12
  6. data/app/controllers/solid_stack_web/application_controller.rb +1 -1
  7. data/app/controllers/solid_stack_web/dashboard_controller.rb +4 -16
  8. data/app/controllers/solid_stack_web/failed_jobs/selections_controller.rb +10 -4
  9. data/app/controllers/solid_stack_web/history_controller.rb +42 -0
  10. data/app/controllers/solid_stack_web/metrics_controller.rb +15 -0
  11. data/app/controllers/solid_stack_web/queues/pauses_controller.rb +13 -0
  12. data/app/controllers/solid_stack_web/queues_controller.rb +12 -7
  13. data/app/controllers/solid_stack_web/recurring_tasks/runs_controller.rb +18 -0
  14. data/app/controllers/solid_stack_web/recurring_tasks_controller.rb +7 -0
  15. data/app/controllers/solid_stack_web/scheduled_jobs_controller.rb +52 -0
  16. data/app/controllers/solid_stack_web/stats_controller.rb +39 -0
  17. data/app/helpers/solid_stack_web/application_helper.rb +64 -0
  18. data/app/javascript/solid_stack_web/application.js +5 -1
  19. data/app/javascript/solid_stack_web/refresh_controller.js +52 -0
  20. data/app/javascript/solid_stack_web/sparkline_tooltip_controller.js +23 -0
  21. data/app/models/solid_stack_web/alert_webhook.rb +67 -0
  22. data/app/models/solid_stack_web/cable_stats.rb +10 -0
  23. data/app/models/solid_stack_web/cache_stats.rb +10 -0
  24. data/app/models/solid_stack_web/queue_depth_sparkline.rb +30 -0
  25. data/app/models/solid_stack_web/queue_stats.rb +34 -0
  26. data/app/models/solid_stack_web/throughput_sparkline.rb +23 -0
  27. data/app/views/layouts/solid_stack_web/application.html.erb +6 -0
  28. data/app/views/solid_stack_web/dashboard/index.html.erb +37 -2
  29. data/app/views/solid_stack_web/history/index.html.erb +76 -0
  30. data/app/views/solid_stack_web/jobs/index.html.erb +26 -3
  31. data/app/views/solid_stack_web/processes/index.html.erb +3 -0
  32. data/app/views/solid_stack_web/queues/index.html.erb +10 -5
  33. data/app/views/solid_stack_web/queues/show.html.erb +67 -0
  34. data/app/views/solid_stack_web/recurring_tasks/index.html.erb +67 -0
  35. data/app/views/solid_stack_web/scheduled_jobs/update.turbo_stream.erb +9 -0
  36. data/app/views/solid_stack_web/stats/index.html.erb +48 -0
  37. data/config/importmap.rb +4 -0
  38. data/config/routes.rb +15 -5
  39. data/lib/solid_stack_web/version.rb +1 -1
  40. data/lib/solid_stack_web.rb +37 -1
  41. metadata +22 -2
@@ -0,0 +1,67 @@
1
+ <div class="sqw-page-header">
2
+ <h1 class="sqw-page-title">Recurring Tasks</h1>
3
+ </div>
4
+
5
+ <% if @recurring_tasks.any? %>
6
+ <table class="sqw-table">
7
+ <thead>
8
+ <tr>
9
+ <th>Key</th>
10
+ <th>Schedule</th>
11
+ <th>Job / Command</th>
12
+ <th>Queue</th>
13
+ <th>Next Run</th>
14
+ <th>Last Run</th>
15
+ <th>Type</th>
16
+ <th></th>
17
+ </tr>
18
+ </thead>
19
+ <tbody>
20
+ <% @recurring_tasks.each do |task| %>
21
+ <tr>
22
+ <td class="sqw-monospace"><%= task.key %></td>
23
+ <td class="sqw-monospace"><%= task.schedule %></td>
24
+ <td>
25
+ <% if task.class_name.present? %>
26
+ <span class="sqw-monospace"><%= task.class_name %></span>
27
+ <% if task.arguments.present? %>
28
+ <div class="sqw-muted sqw-monospace" style="font-size: 11px;"><%= task.arguments.inspect %></div>
29
+ <% end %>
30
+ <% else %>
31
+ <span class="sqw-monospace sqw-muted"><%= task.command %></span>
32
+ <% end %>
33
+ <% if task.description.present? %>
34
+ <div class="sqw-muted" style="font-size: 12px; margin-top: 0.2rem;"><%= task.description %></div>
35
+ <% end %>
36
+ </td>
37
+ <td><span class="sqw-badge sqw-badge--queue"><%= task.queue_name.presence || "default" %></span></td>
38
+ <td class="sqw-muted sqw-monospace">
39
+ <% next_run = begin; task.next_time.strftime("%b %d %H:%M"); rescue; nil; end %>
40
+ <%= next_run || "—" %>
41
+ </td>
42
+ <td class="sqw-muted sqw-monospace">
43
+ <% last_run = task.last_enqueued_time %>
44
+ <%= last_run ? last_run.strftime("%b %d %H:%M") : "—" %>
45
+ </td>
46
+ <td>
47
+ <% if task.static? %>
48
+ <span class="sqw-badge sqw-badge--scheduled">Static</span>
49
+ <% else %>
50
+ <span class="sqw-badge sqw-badge--blocked">Dynamic</span>
51
+ <% end %>
52
+ </td>
53
+ <td class="sqw-actions">
54
+ <%= button_to "Run Now", recurring_task_run_path(task.key),
55
+ method: :post,
56
+ class: "sqw-btn sqw-btn--sm",
57
+ data: { turbo_confirm: "Run \"#{task.key}\" immediately?" } %>
58
+ </td>
59
+ </tr>
60
+ <% end %>
61
+ </tbody>
62
+ </table>
63
+ <% else %>
64
+ <div class="sqw-empty">
65
+ <p>No recurring tasks configured.</p>
66
+ </div>
67
+ <% end %>
@@ -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="sqw-muted">
6
+ <%= @execution.scheduled_at.strftime("%b %d %H:%M") %>
7
+ </td>
8
+ <% end %>
9
+ <% end %>
@@ -0,0 +1,48 @@
1
+ <div class="sqw-page-header">
2
+ <h1 class="sqw-page-title">Performance Stats</h1>
3
+ </div>
4
+
5
+ <% if @stats.any? %>
6
+ <table class="sqw-table">
7
+ <thead>
8
+ <tr>
9
+ <% [
10
+ ["class_name", "Job Class"],
11
+ ["count", "Executions"],
12
+ ["avg", "Avg"],
13
+ ["p50", "p50"],
14
+ ["p95", "p95"],
15
+ ["min", "Min"],
16
+ ["max", "Max"]
17
+ ].each do |col, label| %>
18
+ <th>
19
+ <% next_dir = (@sort == col && @direction == "desc") ? "asc" : "desc" %>
20
+ <%= link_to stats_path(sort: col, direction: next_dir) do %>
21
+ <%= label %>
22
+ <% if @sort == col %>
23
+ <span class="sqw-sort-indicator"><%= @direction == "desc" ? "↓" : "↑" %></span>
24
+ <% end %>
25
+ <% end %>
26
+ </th>
27
+ <% end %>
28
+ </tr>
29
+ </thead>
30
+ <tbody>
31
+ <% @stats.each do |row| %>
32
+ <tr>
33
+ <td class="sqw-monospace"><%= row[:class_name] %></td>
34
+ <td><%= row[:count] %></td>
35
+ <td class="sqw-muted"><%= format_duration(row[:avg]) %></td>
36
+ <td class="sqw-muted"><%= format_duration(row[:p50]) %></td>
37
+ <td><strong><%= format_duration(row[:p95]) %></strong></td>
38
+ <td class="sqw-muted"><%= format_duration(row[:min]) %></td>
39
+ <td class="sqw-muted"><%= format_duration(row[:max]) %></td>
40
+ </tr>
41
+ <% end %>
42
+ </tbody>
43
+ </table>
44
+ <% else %>
45
+ <div class="sqw-empty">
46
+ <p>No finished jobs yet.</p>
47
+ </div>
48
+ <% end %>
data/config/importmap.rb CHANGED
@@ -1,2 +1,6 @@
1
+ pin "@hotwired/turbo", to: "https://cdn.jsdelivr.net/npm/@hotwired/turbo@8.0.23/dist/turbo.es2017-esm.js"
2
+ pin "@hotwired/stimulus", to: "https://cdn.jsdelivr.net/npm/@hotwired/stimulus@3.2.2/dist/stimulus.js"
1
3
  pin "solid_stack_web", to: "solid_stack_web/application.js"
4
+ pin "solid_stack_web/refresh_controller", to: "solid_stack_web/refresh_controller.js"
2
5
  pin "solid_stack_web/selection_controller", to: "solid_stack_web/selection_controller.js"
6
+ pin "solid_stack_web/sparkline_tooltip_controller", to: "solid_stack_web/sparkline_tooltip_controller.js"
data/config/routes.rb CHANGED
@@ -4,6 +4,16 @@ SolidStackWeb::Engine.routes.draw do
4
4
  resource :job_selection, path: "jobs/selection", only: [:destroy], controller: "jobs/selections"
5
5
  resource :failed_job_selection, path: "failed_jobs/selection", only: [:create, :destroy], controller: "failed_jobs/selections"
6
6
 
7
+ resources :recurring_tasks, only: [:index], param: :key do
8
+ resource :run, only: [:create], controller: "recurring_tasks/runs"
9
+ end
10
+
11
+ resources :scheduled_jobs, only: [:update] do
12
+ collection do
13
+ post :run_all_now, action: :create
14
+ end
15
+ end
16
+
7
17
  resources :jobs, only: [:index, :show, :destroy] do
8
18
  collection do
9
19
  post :discard_all, action: :destroy
@@ -15,15 +25,15 @@ SolidStackWeb::Engine.routes.draw do
15
25
  resource :arguments, only: [:update], controller: "failed_jobs/arguments"
16
26
  end
17
27
 
18
- resources :queues, only: [:index] do
19
- member do
20
- post :pause
21
- delete :resume
22
- end
28
+ resources :queues, only: [:index, :show] do
29
+ resource :pause, only: [:create, :destroy], controller: "queues/pauses"
23
30
  end
24
31
 
25
32
  resources :processes, only: [:index]
26
33
 
34
+ get "metrics", to: "metrics#index", as: :metrics
35
+ get "stats", to: "stats#index", as: :stats
36
+ get "history", to: "history#index", as: :history
27
37
  get "cache", to: "cache#index", as: :cache
28
38
  get "cable", to: "cable#index", as: :cable
29
39
  end
@@ -1,3 +1,3 @@
1
1
  module SolidStackWeb
2
- VERSION = "0.2.0"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -3,7 +3,11 @@ require "solid_stack_web/engine"
3
3
 
4
4
  module SolidStackWeb
5
5
  class << self
6
- attr_writer :page_size, :connects_to
6
+ attr_writer :page_size, :connects_to, :slow_job_threshold,
7
+ :alert_webhook_url, :alert_webhook_cooldown,
8
+ :alert_failure_threshold, :alert_queue_thresholds,
9
+ :dashboard_refresh_interval, :default_refresh_interval,
10
+ :search_results_limit
7
11
 
8
12
  def page_size
9
13
  @page_size || 25
@@ -13,6 +17,38 @@ module SolidStackWeb
13
17
  @connects_to
14
18
  end
15
19
 
20
+ def slow_job_threshold
21
+ @slow_job_threshold
22
+ end
23
+
24
+ def alert_webhook_url
25
+ @alert_webhook_url
26
+ end
27
+
28
+ def alert_webhook_cooldown
29
+ @alert_webhook_cooldown || 3600
30
+ end
31
+
32
+ def alert_failure_threshold
33
+ @alert_failure_threshold
34
+ end
35
+
36
+ def alert_queue_thresholds
37
+ @alert_queue_thresholds || {}
38
+ end
39
+
40
+ def dashboard_refresh_interval
41
+ @dashboard_refresh_interval || 5_000
42
+ end
43
+
44
+ def default_refresh_interval
45
+ @default_refresh_interval || 10_000
46
+ end
47
+
48
+ def search_results_limit
49
+ @search_results_limit || 25
50
+ end
51
+
16
52
  def configure
17
53
  yield self
18
54
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solid_stack_web
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chuck Smith
@@ -150,14 +150,29 @@ files:
150
150
  - app/controllers/solid_stack_web/failed_jobs/arguments_controller.rb
151
151
  - app/controllers/solid_stack_web/failed_jobs/selections_controller.rb
152
152
  - app/controllers/solid_stack_web/failed_jobs_controller.rb
153
+ - app/controllers/solid_stack_web/history_controller.rb
153
154
  - app/controllers/solid_stack_web/jobs/selections_controller.rb
154
155
  - app/controllers/solid_stack_web/jobs_controller.rb
156
+ - app/controllers/solid_stack_web/metrics_controller.rb
155
157
  - app/controllers/solid_stack_web/processes_controller.rb
158
+ - app/controllers/solid_stack_web/queues/pauses_controller.rb
156
159
  - app/controllers/solid_stack_web/queues_controller.rb
160
+ - app/controllers/solid_stack_web/recurring_tasks/runs_controller.rb
161
+ - app/controllers/solid_stack_web/recurring_tasks_controller.rb
162
+ - app/controllers/solid_stack_web/scheduled_jobs_controller.rb
163
+ - app/controllers/solid_stack_web/stats_controller.rb
157
164
  - app/helpers/solid_stack_web/application_helper.rb
158
165
  - app/javascript/solid_stack_web/application.js
166
+ - app/javascript/solid_stack_web/refresh_controller.js
159
167
  - app/javascript/solid_stack_web/selection_controller.js
168
+ - app/javascript/solid_stack_web/sparkline_tooltip_controller.js
169
+ - app/models/solid_stack_web/alert_webhook.rb
170
+ - app/models/solid_stack_web/cable_stats.rb
171
+ - app/models/solid_stack_web/cache_stats.rb
160
172
  - app/models/solid_stack_web/job.rb
173
+ - app/models/solid_stack_web/queue_depth_sparkline.rb
174
+ - app/models/solid_stack_web/queue_stats.rb
175
+ - app/models/solid_stack_web/throughput_sparkline.rb
161
176
  - app/views/layouts/solid_stack_web/application.html.erb
162
177
  - app/views/solid_stack_web/cable/index.html.erb
163
178
  - app/views/solid_stack_web/cache/index.html.erb
@@ -165,12 +180,17 @@ files:
165
180
  - app/views/solid_stack_web/failed_jobs/destroy.turbo_stream.erb
166
181
  - app/views/solid_stack_web/failed_jobs/index.html.erb
167
182
  - app/views/solid_stack_web/failed_jobs/show.html.erb
183
+ - app/views/solid_stack_web/history/index.html.erb
168
184
  - app/views/solid_stack_web/jobs/_empty.html.erb
169
185
  - app/views/solid_stack_web/jobs/destroy.turbo_stream.erb
170
186
  - app/views/solid_stack_web/jobs/index.html.erb
171
187
  - app/views/solid_stack_web/jobs/show.html.erb
172
188
  - app/views/solid_stack_web/processes/index.html.erb
173
189
  - app/views/solid_stack_web/queues/index.html.erb
190
+ - app/views/solid_stack_web/queues/show.html.erb
191
+ - app/views/solid_stack_web/recurring_tasks/index.html.erb
192
+ - app/views/solid_stack_web/scheduled_jobs/update.turbo_stream.erb
193
+ - app/views/solid_stack_web/stats/index.html.erb
174
194
  - config/importmap.rb
175
195
  - config/routes.rb
176
196
  - lib/solid_stack_web.rb
@@ -198,7 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
198
218
  - !ruby/object:Gem::Version
199
219
  version: '0'
200
220
  requirements: []
201
- rubygems_version: 4.0.10
221
+ rubygems_version: 4.0.12
202
222
  specification_version: 4
203
223
  summary: A unified Rails engine dashboard for Solid Queue, Solid Cache, and Solid
204
224
  Cable.