solid_queue_lite 0.1.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 +7 -0
- data/CHANGELOG.md +10 -0
- data/MIT-LICENSE +20 -0
- data/README.md +142 -0
- data/Rakefile +3 -0
- data/app/assets/stylesheets/soliq_queue_lite/application.css +15 -0
- data/app/controllers/concerns/solid_queue_lite/approximate_countable.rb +10 -0
- data/app/controllers/solid_queue_lite/application_controller.rb +4 -0
- data/app/controllers/solid_queue_lite/dashboards_controller.rb +61 -0
- data/app/controllers/solid_queue_lite/jobs_controller.rb +129 -0
- data/app/controllers/solid_queue_lite/processes_controller.rb +39 -0
- data/app/controllers/solid_queue_lite/queues_controller.rb +31 -0
- data/app/helpers/solid_queue_lite/application_helper.rb +27 -0
- data/app/jobs/solid_queue_lite/application_job.rb +4 -0
- data/app/jobs/solid_queue_lite/telemetry_sampler_job.rb +11 -0
- data/app/models/solid_queue_lite/application_record.rb +5 -0
- data/app/models/solid_queue_lite/stat.rb +7 -0
- data/app/views/layouts/solid_queue_lite/application.html.erb +383 -0
- data/app/views/solid_queue_lite/dashboards/show.html.erb +573 -0
- data/config/routes.rb +30 -0
- data/db/migrate/20260406000000_create_solid_queue_lite_stats.rb +16 -0
- data/lib/solid_queue_lite/approximate_counter.rb +87 -0
- data/lib/solid_queue_lite/engine.rb +20 -0
- data/lib/solid_queue_lite/install.rb +107 -0
- data/lib/solid_queue_lite/jobs.rb +236 -0
- data/lib/solid_queue_lite/processes.rb +156 -0
- data/lib/solid_queue_lite/telemetry.rb +201 -0
- data/lib/solid_queue_lite/version.rb +3 -0
- data/lib/solid_queue_lite.rb +46 -0
- data/lib/tasks/solid_queue_lite_tasks.rake +14 -0
- metadata +116 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 8794ace8f2ebf4cfcaf14e887c2a166f660ee6a91e6cb381052efa29d6bb913f
|
|
4
|
+
data.tar.gz: 7d0b0b3fbe10136b7ef29f75686c05943a8db655d5025795f54c7ea92273a09e
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: e0ce386dc14caf232ef48431d826029d9bd17cfd6dda08840e28c7779015230589f9c503a8773287ed0b59feaafa26c8489cb9569ad340234c45122e4456da59
|
|
7
|
+
data.tar.gz: 26962200de4d9e6d126dbac23eb84d6ea6c92cda64e0c4993daea15aedf498b5e7c32836467fdde96caf6137a80150511ba1d92a6f9e6bdb246dfd69cfae0b54
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
- Initial public release of Solid Queue Lite.
|
|
6
|
+
- Added a mockup-aligned dashboard experience for pulse, jobs, processes, and recurring tasks.
|
|
7
|
+
- Added queue discovery from Solid Queue worker configuration and process metadata.
|
|
8
|
+
- Added exact queue and telemetry counts for fresh installs.
|
|
9
|
+
- Added recurring task monitoring with last-run and next-run visibility.
|
|
10
|
+
- Added queue control actions, job drill-downs, retry/discard operations, and telemetry sampling support.
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright nanda suhendra
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Solid Queue Lite
|
|
2
|
+
|
|
3
|
+
A minimal, zero-build web interface for [Solid Queue](https://github.com/rails/solid_queue).
|
|
4
|
+
|
|
5
|
+
[](https://rubygems.org/gems/solid_queue_lite)
|
|
6
|
+
|
|
7
|
+
The official `mission_control-jobs` engine is great, but it brings along Turbo, Stimulus, and expects a standard Rails asset pipeline. If you run an API-only app, use a modern JS framework, or just want to avoid frontend dependencies in your infrastructure tooling, Solid Queue Lite provides the same operational visibility without the build-step baggage.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
Add the engine to your host application's Gemfile:
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
gem "solid_queue_lite"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Install dependencies, then run the engine migration:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
bundle install
|
|
21
|
+
bin/rails solid_queue_lite:install
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The installer copies the engine migration into the host app and creates `config/initializers/solid_queue_lite.rb` if it does not already exist.
|
|
25
|
+
|
|
26
|
+
Run the migration separately, or let the installer do it for you:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
bin/rails db:migrate
|
|
30
|
+
# or
|
|
31
|
+
bin/rails solid_queue_lite:install MIGRATE=1
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Mount the engine behind your application's own authentication boundary:
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
# config/routes.rb
|
|
38
|
+
authenticate :user, ->(user) { user.admin? } do
|
|
39
|
+
mount SolidQueueLite::Engine => "/ops/jobs"
|
|
40
|
+
end
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The engine root renders the dashboard at `/ops/jobs`, and the jobs index is available at `/ops/jobs/jobs`.
|
|
44
|
+
|
|
45
|
+
## Requirements
|
|
46
|
+
|
|
47
|
+
- Ruby 3.1+
|
|
48
|
+
- Rails 7.1+
|
|
49
|
+
- Solid Queue 1.x
|
|
50
|
+
|
|
51
|
+
## Host Configuration
|
|
52
|
+
|
|
53
|
+
Use the configuration block to scope all dashboard reads in multi-tenant deployments:
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
# config/initializers/solid_queue_lite.rb
|
|
57
|
+
SolidQueueLite.configure do |config|
|
|
58
|
+
config.tenant_scope = lambda do |relation|
|
|
59
|
+
relation.where(queue_name: Current.account.solid_queue_prefix)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The lambda receives the Active Record relation before it is queried.
|
|
65
|
+
|
|
66
|
+
## Telemetry Sampling
|
|
67
|
+
|
|
68
|
+
The engine ships with `SolidQueueLite::TelemetrySamplerJob`, which writes aggregate queue snapshots into `solid_queue_lite_stats` and prunes samples older than 7 days.
|
|
69
|
+
|
|
70
|
+
If you use Solid Queue recurring tasks, schedule the sampler in your host application's recurring configuration:
|
|
71
|
+
|
|
72
|
+
```yml
|
|
73
|
+
# config/recurring.yml
|
|
74
|
+
production:
|
|
75
|
+
solid_queue_lite_telemetry:
|
|
76
|
+
class: SolidQueueLite::TelemetrySamplerJob
|
|
77
|
+
schedule: every 5 minutes
|
|
78
|
+
queue: default
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Without a scheduler process, the dashboard still renders, but the historical charts stay empty until samples are written.
|
|
82
|
+
|
|
83
|
+
## Console And Tasks
|
|
84
|
+
|
|
85
|
+
The reusable logic now lives under `lib/solid_queue_lite`, so you can call the same APIs from a Rails console:
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
SolidQueueLite::Telemetry.sample!
|
|
89
|
+
SolidQueueLite::Telemetry.backfill!
|
|
90
|
+
SolidQueueLite::Telemetry.dashboard_data(range_key: "24h")
|
|
91
|
+
|
|
92
|
+
SolidQueueLite::Jobs.list(state_key: "failed", page: 1, per_page: 50)
|
|
93
|
+
SolidQueueLite::Jobs.find(123)
|
|
94
|
+
|
|
95
|
+
SolidQueueLite::Processes.index_data
|
|
96
|
+
SolidQueueLite::Processes.pause_queue!("background")
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
To force an immediate current telemetry snapshot after upgrading, run:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
bin/rake solid_queue_lite:telemetry:backfill
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The historical `scheduled_count` and `success_count` series cannot be reconstructed exactly for old rows because Solid Queue does not retain that event history. The backfill task writes or refreshes a current snapshot immediately so upgraded installs do not need to wait for the next scheduled sample.
|
|
106
|
+
|
|
107
|
+
### Core Design Decisions
|
|
108
|
+
|
|
109
|
+
- **Zero Asset Pipeline:** The UI is built with raw HTML, Pico.css, and Alpine.js loaded via CDN. It adds nothing to your app's frontend build.
|
|
110
|
+
- **Database Safe:** Standard job dashboards often kill primary databases with naive `COUNT(*)` queries on massive tables. This engine strictly uses database metadata (e.g., `pg_class` in Postgres) for approximate counting to prevent sequential scans and lock contention.
|
|
111
|
+
- **Built-in Telemetry:** Solid Queue doesn't store historical data. This engine includes a lightweight, self-pruning background job that snapshots queue sizes, latency, and error rates, giving you 24-hour trends without needing an external APM.
|
|
112
|
+
- **Multi-tenant Support:** Exposes a simple configuration block to scope the dashboard's database queries, allowing you to isolate job visibility per tenant.
|
|
113
|
+
|
|
114
|
+
### Features
|
|
115
|
+
|
|
116
|
+
- Monitor active Supervisors, Workers, and Dispatchers.
|
|
117
|
+
- Filter and inspect Ready, In-Progress, Scheduled, and Failed jobs.
|
|
118
|
+
- View job arguments (JSON), full stack traces, and execute individual or bulk retries/discards.
|
|
119
|
+
- Configurable auto-refresh that automatically pauses when you interact with the UI to prevent state loss.
|
|
120
|
+
- Monitor recurring task schedule, last run time, next run time, and latest status from a dedicated dashboard tab.
|
|
121
|
+
|
|
122
|
+
## Releasing
|
|
123
|
+
|
|
124
|
+
Build the gem locally before publishing:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
gem build solid_queue_lite.gemspec
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Publish to RubyGems:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
gem push solid_queue_lite-0.1.0.gem
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Typical release flow:
|
|
137
|
+
|
|
138
|
+
1. Update `lib/solid_queue_lite/version.rb`.
|
|
139
|
+
2. Update `CHANGELOG.md`.
|
|
140
|
+
3. Commit and tag the release.
|
|
141
|
+
4. Build with `gem build solid_queue_lite.gemspec`.
|
|
142
|
+
5. Push with `gem push <built-gem-file>`.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
|
3
|
+
* listed below.
|
|
4
|
+
*
|
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
|
7
|
+
*
|
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
|
11
|
+
* It is generally better to create a new file per style scope.
|
|
12
|
+
*
|
|
13
|
+
*= require_tree .
|
|
14
|
+
*= require_self
|
|
15
|
+
*/
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module SolidQueueLite
|
|
2
|
+
class DashboardsController < ApplicationController
|
|
3
|
+
DASHBOARD_TABS = %w[pulse jobs processes recurring].freeze
|
|
4
|
+
DASHBOARD_PER_PAGE = 25
|
|
5
|
+
|
|
6
|
+
def show
|
|
7
|
+
telemetry_data = SolidQueueLite::Telemetry.dashboard_data(range_key: params.fetch(:range, "24h"))
|
|
8
|
+
process_data = SolidQueueLite::Processes.index_data
|
|
9
|
+
|
|
10
|
+
@active_tab = requested_tab
|
|
11
|
+
@selected_range = telemetry_data[:selected_range]
|
|
12
|
+
@stats = telemetry_data[:stats]
|
|
13
|
+
@latest_stat = telemetry_data[:latest_stat]
|
|
14
|
+
@current_ready_count = telemetry_data[:current_ready_count]
|
|
15
|
+
@current_scheduled_count = telemetry_data[:current_scheduled_count]
|
|
16
|
+
@current_failed_count = telemetry_data[:current_failed_count]
|
|
17
|
+
@worker_count = telemetry_data[:worker_count]
|
|
18
|
+
@dispatcher_count = telemetry_data[:dispatcher_count]
|
|
19
|
+
@stale_process_count = telemetry_data[:stale_process_count]
|
|
20
|
+
@recurring_tasks = telemetry_data[:recurring_tasks]
|
|
21
|
+
@chart_payload = telemetry_data[:chart_payload]
|
|
22
|
+
|
|
23
|
+
@processes = process_data[:processes]
|
|
24
|
+
@heartbeat = process_data[:heartbeat]
|
|
25
|
+
@queues = process_data[:queues]
|
|
26
|
+
|
|
27
|
+
@selected_queue_name = params[:queue_name].presence
|
|
28
|
+
@selected_queue_metrics = @queues.find { |queue| queue[:name] == @selected_queue_name }
|
|
29
|
+
@jobs_selected_state = params.fetch(:state, "failed")
|
|
30
|
+
@jobs_per_page = SolidQueueLite::Jobs.normalize_per_page(params.fetch(:per_page, DASHBOARD_PER_PAGE))
|
|
31
|
+
@jobs_page = SolidQueueLite::Jobs.normalize_page(params.fetch(:page, 1))
|
|
32
|
+
|
|
33
|
+
if @selected_queue_name.present?
|
|
34
|
+
jobs_data = SolidQueueLite::Jobs.list(
|
|
35
|
+
state_key: @jobs_selected_state,
|
|
36
|
+
page: @jobs_page,
|
|
37
|
+
per_page: @jobs_per_page,
|
|
38
|
+
queue_name: @selected_queue_name,
|
|
39
|
+
include_details: true
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
@jobs = jobs_data[:jobs]
|
|
43
|
+
@jobs_pagination = jobs_data[:pagination]
|
|
44
|
+
else
|
|
45
|
+
@jobs = []
|
|
46
|
+
@jobs_pagination = {
|
|
47
|
+
page: @jobs_page,
|
|
48
|
+
per_page: @jobs_per_page,
|
|
49
|
+
total_pages: 1,
|
|
50
|
+
approximate_total_count: 0
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
def requested_tab
|
|
57
|
+
requested_value = params[:tab].presence || "pulse"
|
|
58
|
+
DASHBOARD_TABS.include?(requested_value) ? requested_value : "pulse"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
module SolidQueueLite
|
|
2
|
+
class JobsController < ApplicationController
|
|
3
|
+
rescue_from ::ActiveRecord::RecordNotFound, with: :render_not_found
|
|
4
|
+
|
|
5
|
+
def index
|
|
6
|
+
state_key = requested_state_key
|
|
7
|
+
data = SolidQueueLite::Jobs.list(
|
|
8
|
+
state_key: state_key,
|
|
9
|
+
page: requested_page,
|
|
10
|
+
per_page: requested_per_page,
|
|
11
|
+
queue_name: params[:queue_name],
|
|
12
|
+
include_details: true
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
@jobs = data[:jobs]
|
|
16
|
+
@selected_state = data[:selected_state]
|
|
17
|
+
@state_options = data[:state_options]
|
|
18
|
+
@selected_queue_name = data[:selected_queue_name]
|
|
19
|
+
@pagination = data[:pagination]
|
|
20
|
+
|
|
21
|
+
respond_to do |format|
|
|
22
|
+
format.json do
|
|
23
|
+
render json: {
|
|
24
|
+
jobs: @jobs,
|
|
25
|
+
pagination: @pagination,
|
|
26
|
+
filters: {
|
|
27
|
+
state: state_key
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def show
|
|
35
|
+
@job = SolidQueueLite::Jobs.find(params[:id])
|
|
36
|
+
|
|
37
|
+
respond_to do |format|
|
|
38
|
+
format.json { render json: SolidQueueLite::Jobs.serialize(@job) }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def bulk_retry
|
|
43
|
+
retried_count = SolidQueueLite::Jobs.bulk_retry!(job_ids: params[:job_ids], state_key: params.fetch(:state, "failed"))
|
|
44
|
+
|
|
45
|
+
respond_to do |format|
|
|
46
|
+
format.json { render json: { retried: retried_count } }
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def bulk_discard
|
|
51
|
+
discarded_count = SolidQueueLite::Jobs.bulk_discard!(job_ids: params[:job_ids], state_key: params.fetch(:state, requested_state_key))
|
|
52
|
+
|
|
53
|
+
respond_to do |format|
|
|
54
|
+
format.json { render json: { discarded: discarded_count } }
|
|
55
|
+
end
|
|
56
|
+
rescue ::SolidQueue::Execution::UndiscardableError => error
|
|
57
|
+
render_unprocessable_entity(error)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def retry
|
|
61
|
+
job = SolidQueueLite::Jobs.retry!(params[:id])
|
|
62
|
+
|
|
63
|
+
respond_to do |format|
|
|
64
|
+
format.json do
|
|
65
|
+
render json: {
|
|
66
|
+
id: job.id,
|
|
67
|
+
retried: true,
|
|
68
|
+
state: "ready"
|
|
69
|
+
}
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def discard
|
|
75
|
+
job, previous_state = SolidQueueLite::Jobs.discard!(params[:id])
|
|
76
|
+
|
|
77
|
+
respond_to do |format|
|
|
78
|
+
format.json do
|
|
79
|
+
render json: {
|
|
80
|
+
id: job.id,
|
|
81
|
+
discarded: true,
|
|
82
|
+
previous_state: previous_state
|
|
83
|
+
}
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
rescue ::SolidQueue::Execution::UndiscardableError => error
|
|
87
|
+
render_unprocessable_entity(error)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
def requested_page
|
|
92
|
+
SolidQueueLite::Jobs.normalize_page(params.fetch(:page, 1))
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def requested_per_page
|
|
96
|
+
SolidQueueLite::Jobs.normalize_per_page(params.fetch(:per_page, SolidQueueLite::Jobs::DEFAULT_PER_PAGE))
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def requested_state_key
|
|
100
|
+
params.fetch(:state, "ready")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def requested_state(state_key = requested_state_key)
|
|
104
|
+
SolidQueueLite::Jobs.resolve_state(state_key)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def jobs_redirect_params(default_state: "failed")
|
|
108
|
+
SolidQueueLite::Jobs.jobs_redirect_params(params, default_state: default_state)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def redirect_target(default_state: "failed")
|
|
112
|
+
return params[:return_to] if params[:return_to].to_s.start_with?("/")
|
|
113
|
+
|
|
114
|
+
jobs_path(jobs_redirect_params(default_state: default_state))
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def render_not_found
|
|
118
|
+
respond_to do |format|
|
|
119
|
+
format.json { render json: { error: "Not found" }, status: :not_found }
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def render_unprocessable_entity(error)
|
|
124
|
+
respond_to do |format|
|
|
125
|
+
format.json { render json: { error: error.message }, status: :unprocessable_entity }
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module SolidQueueLite
|
|
2
|
+
class ProcessesController < ApplicationController
|
|
3
|
+
def index
|
|
4
|
+
data = SolidQueueLite::Processes.index_data
|
|
5
|
+
@processes = data[:processes]
|
|
6
|
+
@heartbeat = data[:heartbeat]
|
|
7
|
+
@queues = data[:queues]
|
|
8
|
+
|
|
9
|
+
respond_to do |format|
|
|
10
|
+
format.json do
|
|
11
|
+
render json: {
|
|
12
|
+
processes: @processes,
|
|
13
|
+
heartbeat: @heartbeat
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def prune
|
|
20
|
+
prunable_before = SolidQueueLite::Processes.prune!
|
|
21
|
+
|
|
22
|
+
respond_to do |format|
|
|
23
|
+
format.json do
|
|
24
|
+
render json: {
|
|
25
|
+
pruned: true,
|
|
26
|
+
approximate_pruned_count: prunable_before
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
def redirect_target
|
|
34
|
+
return params[:return_to] if params[:return_to].to_s.start_with?("/")
|
|
35
|
+
|
|
36
|
+
processes_path
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module SolidQueueLite
|
|
2
|
+
class QueuesController < ApplicationController
|
|
3
|
+
def index
|
|
4
|
+
redirect_to processes_path
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def pause
|
|
8
|
+
SolidQueueLite::Processes.pause_queue!(params.fetch(:queue_name))
|
|
9
|
+
redirect_to redirect_target, notice: "Paused queue #{params[:queue_name]}"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def resume
|
|
13
|
+
SolidQueueLite::Processes.resume_queue!(params.fetch(:queue_name))
|
|
14
|
+
redirect_to redirect_target, notice: "Resumed queue #{params[:queue_name]}"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def clear
|
|
18
|
+
SolidQueueLite::Processes.clear_queue!(params.fetch(:queue_name))
|
|
19
|
+
redirect_to redirect_target, notice: "Cleared ready jobs from queue #{params[:queue_name]}"
|
|
20
|
+
rescue ::SolidQueue::Execution::UndiscardableError => error
|
|
21
|
+
redirect_to redirect_target, alert: error.message
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
def redirect_target
|
|
26
|
+
return params[:return_to] if params[:return_to].to_s.start_with?("/")
|
|
27
|
+
|
|
28
|
+
processes_path
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module SolidQueueLite
|
|
2
|
+
module ApplicationHelper
|
|
3
|
+
def dashboard_route_params(overrides = {})
|
|
4
|
+
{
|
|
5
|
+
tab: params[:tab].presence || "pulse",
|
|
6
|
+
range: params[:range].presence || "24h",
|
|
7
|
+
queue_name: params[:queue_name].presence,
|
|
8
|
+
state: params[:state].presence || "failed",
|
|
9
|
+
page: params[:page].presence,
|
|
10
|
+
per_page: params[:per_page].presence
|
|
11
|
+
}.merge(overrides).compact
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def dashboard_return_to(overrides = {})
|
|
15
|
+
root_path(dashboard_route_params(overrides))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def dashboard_relative_time(timestamp)
|
|
19
|
+
return "n/a" unless timestamp
|
|
20
|
+
return "Just now" if timestamp >= 1.minute.ago
|
|
21
|
+
|
|
22
|
+
I18n.with_locale(:en) do
|
|
23
|
+
"#{time_ago_in_words(timestamp)} ago"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|