solid_queue_monitor 0.1.2 → 0.3.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 +25 -11
- data/Rakefile +8 -8
- data/app/controllers/solid_queue_monitor/application_controller.rb +25 -0
- data/app/controllers/solid_queue_monitor/base_controller.rb +197 -0
- data/app/controllers/solid_queue_monitor/failed_jobs_controller.rb +63 -0
- data/app/controllers/solid_queue_monitor/in_progress_jobs_controller.rb +33 -0
- data/app/controllers/solid_queue_monitor/overview_controller.rb +26 -0
- data/app/controllers/solid_queue_monitor/queues_controller.rb +13 -0
- data/app/controllers/solid_queue_monitor/ready_jobs_controller.rb +15 -0
- data/app/controllers/solid_queue_monitor/recurring_jobs_controller.rb +15 -0
- data/app/controllers/solid_queue_monitor/scheduled_jobs_controller.rb +25 -0
- data/app/presenters/solid_queue_monitor/base_presenter.rb +44 -39
- data/app/presenters/solid_queue_monitor/failed_jobs_presenter.rb +51 -45
- data/app/presenters/solid_queue_monitor/in_progress_jobs_presenter.rb +82 -0
- data/app/presenters/solid_queue_monitor/jobs_presenter.rb +46 -3
- data/app/presenters/solid_queue_monitor/queues_presenter.rb +5 -5
- data/app/presenters/solid_queue_monitor/ready_jobs_presenter.rb +10 -2
- data/app/presenters/solid_queue_monitor/recurring_jobs_presenter.rb +5 -2
- data/app/presenters/solid_queue_monitor/scheduled_jobs_presenter.rb +15 -9
- data/app/presenters/solid_queue_monitor/stats_presenter.rb +5 -3
- data/app/services/solid_queue_monitor/authentication_service.rb +7 -5
- data/app/services/solid_queue_monitor/execute_job_service.rb +3 -1
- data/app/services/solid_queue_monitor/failed_job_service.rb +38 -42
- data/app/services/solid_queue_monitor/html_generator.rb +7 -3
- data/app/services/solid_queue_monitor/pagination_service.rb +3 -1
- data/app/services/solid_queue_monitor/stats_calculator.rb +4 -1
- data/app/services/solid_queue_monitor/status_calculator.rb +4 -1
- data/app/services/solid_queue_monitor/stylesheet_generator.rb +23 -21
- data/config/initializers/solid_queue_monitor.rb +3 -1
- data/config/routes.rb +18 -16
- data/lib/generators/solid_queue_monitor/install_generator.rb +7 -5
- data/lib/generators/solid_queue_monitor/templates/initializer.rb +3 -1
- data/lib/solid_queue_monitor/engine.rb +5 -3
- data/lib/solid_queue_monitor/version.rb +1 -1
- data/lib/solid_queue_monitor.rb +9 -13
- data/lib/tasks/app.rake +42 -40
- metadata +18 -148
- data/app/controllers/solid_queue_monitor/monitor_controller.rb +0 -318
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d2911139409c2a387a2c425c0ef9927071a05dcf5f718e5aefc7bfb86cc4b7b6
|
4
|
+
data.tar.gz: 398de34669f64b9d4cab2cf1ed7e1f19da6fcd56b67df8da2c2682410308a905
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9357fee483f20555b92b1fd913224c536ae934bb8442968f42470c672c1cc19a8388d13a5cd7741f36158a67c594913074b5cdafbeae8caaa6aa67e5161cc373
|
7
|
+
data.tar.gz: 32a1c6d65dbbcf9d837ded2fca261d0d715546c446a716073881c7a199d7ee3d561a94971880f5c144f270484199e265fd0b367230babd811891409b56849a2e
|
data/README.md
CHANGED
@@ -15,13 +15,16 @@ A lightweight, zero-dependency web interface for monitoring Solid Queue backgrou
|
|
15
15
|
|
16
16
|
## Features
|
17
17
|
|
18
|
-
- **Dashboard Overview**: Get a quick snapshot of your
|
19
|
-
- **
|
20
|
-
- **
|
21
|
-
- **
|
22
|
-
- **
|
23
|
-
- **
|
24
|
-
- **
|
18
|
+
- **Dashboard Overview**: Get a quick snapshot of your queue's health with statistics on all job types
|
19
|
+
- **Ready Jobs**: View jobs that are ready to be executed
|
20
|
+
- **In Progress Jobs**: Monitor jobs currently being processed by workers
|
21
|
+
- **Scheduled Jobs**: See upcoming jobs scheduled for future execution
|
22
|
+
- **Recurring Jobs**: Manage periodic jobs that run on a schedule
|
23
|
+
- **Failed Jobs**: Track and debug failed jobs, with the ability to retry or discard them
|
24
|
+
- **Queue Management**: View and filter jobs by queue
|
25
|
+
- **Advanced Job Filtering**: Filter jobs by class name, queue, status, and job arguments
|
26
|
+
- **Quick Actions**: Retry or discard failed jobs directly from any view
|
27
|
+
- **Performance Optimized**: Designed for high-volume applications with smart pagination
|
25
28
|
- **Optional Authentication**: Secure your dashboard with HTTP Basic Authentication
|
26
29
|
- **Responsive Design**: Works on desktop and mobile devices
|
27
30
|
- **Zero Dependencies**: No additional JavaScript libraries or frameworks required
|
@@ -30,18 +33,18 @@ A lightweight, zero-dependency web interface for monitoring Solid Queue backgrou
|
|
30
33
|
|
31
34
|
### Dashboard Overview
|
32
35
|
|
33
|
-

|
36
|
+

|
34
37
|
|
35
|
-
###
|
38
|
+
### Failed Jobs
|
36
39
|
|
37
|
-

|
38
41
|
|
39
42
|
## Installation
|
40
43
|
|
41
44
|
Add this line to your application's Gemfile:
|
42
45
|
|
43
46
|
```ruby
|
44
|
-
gem 'solid_queue_monitor', '~> 0.
|
47
|
+
gem 'solid_queue_monitor', '~> 0.3.0'
|
45
48
|
```
|
46
49
|
|
47
50
|
Then execute:
|
@@ -109,6 +112,17 @@ The dashboard provides several views:
|
|
109
112
|
|
110
113
|
For API-only Rails applications, SolidQueueMonitor works out of the box without requiring you to enable the asset pipeline or webpacker. This makes it an ideal choice for monitoring background jobs in modern API-based architectures.
|
111
114
|
|
115
|
+
### Job Filtering
|
116
|
+
|
117
|
+
You can filter jobs by:
|
118
|
+
|
119
|
+
- **Class Name**: Filter by job class name
|
120
|
+
- **Queue Name**: Filter by queue name
|
121
|
+
- **Job Arguments**: Search within job arguments using case-insensitive partial matching
|
122
|
+
- **Status**: Filter by job status (completed, failed, scheduled, pending)
|
123
|
+
|
124
|
+
This makes it easy to find specific jobs when debugging issues in your application.
|
125
|
+
|
112
126
|
## Use Cases
|
113
127
|
|
114
128
|
- **Production Monitoring**: Keep an eye on your background job processing in production environments
|
data/Rakefile
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rspec/core/rake_task'
|
5
5
|
|
6
6
|
RSpec::Core::RakeTask.new(:spec)
|
7
7
|
|
8
8
|
task default: :spec
|
9
9
|
|
10
10
|
namespace :db do
|
11
|
-
task :
|
11
|
+
task setup: :environment do
|
12
12
|
require 'fileutils'
|
13
13
|
FileUtils.mkdir_p 'spec/dummy/db'
|
14
|
-
system(
|
15
|
-
system(
|
14
|
+
system('cd spec/dummy && bundle exec rails db:environment:set RAILS_ENV=test')
|
15
|
+
system('cd spec/dummy && bundle exec rails db:schema:load RAILS_ENV=test')
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
task :
|
20
|
-
Rake::Task[
|
19
|
+
task prepare_test_env: :environment do
|
20
|
+
Rake::Task['db:setup'].invoke
|
21
21
|
end
|
22
22
|
|
23
|
-
task :
|
23
|
+
task spec: :prepare_test_env
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidQueueMonitor
|
4
|
+
class ApplicationController < ActionController::Base
|
5
|
+
include ActionController::HttpAuthentication::Basic::ControllerMethods
|
6
|
+
include ActionController::Flash
|
7
|
+
|
8
|
+
before_action :authenticate, if: -> { SolidQueueMonitor::AuthenticationService.authentication_required? }
|
9
|
+
layout false
|
10
|
+
skip_before_action :verify_authenticity_token
|
11
|
+
|
12
|
+
def set_flash_message(message, type)
|
13
|
+
session[:flash_message] = message
|
14
|
+
session[:flash_type] = type
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def authenticate
|
20
|
+
authenticate_or_request_with_http_basic do |username, password|
|
21
|
+
SolidQueueMonitor::AuthenticationService.authenticate(username, password)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidQueueMonitor
|
4
|
+
class BaseController < SolidQueueMonitor::ApplicationController
|
5
|
+
def paginate(relation)
|
6
|
+
PaginationService.new(relation, current_page, per_page).paginate
|
7
|
+
end
|
8
|
+
|
9
|
+
def render_page(title, content)
|
10
|
+
# Get flash message from session
|
11
|
+
message = session[:flash_message]
|
12
|
+
message_type = session[:flash_type]
|
13
|
+
|
14
|
+
# Clear the flash message from session after using it
|
15
|
+
session.delete(:flash_message)
|
16
|
+
session.delete(:flash_type)
|
17
|
+
|
18
|
+
html = SolidQueueMonitor::HtmlGenerator.new(
|
19
|
+
title: title,
|
20
|
+
content: content,
|
21
|
+
message: message,
|
22
|
+
message_type: message_type
|
23
|
+
).generate
|
24
|
+
|
25
|
+
render html: html.html_safe
|
26
|
+
end
|
27
|
+
|
28
|
+
def current_page
|
29
|
+
(params[:page] || 1).to_i
|
30
|
+
end
|
31
|
+
|
32
|
+
def per_page
|
33
|
+
SolidQueueMonitor.jobs_per_page
|
34
|
+
end
|
35
|
+
|
36
|
+
# Preload job statuses to avoid N+1 queries
|
37
|
+
def preload_job_statuses(jobs)
|
38
|
+
return if jobs.empty?
|
39
|
+
|
40
|
+
# Get all job IDs
|
41
|
+
job_ids = jobs.map(&:id)
|
42
|
+
|
43
|
+
# Find all failed jobs in a single query
|
44
|
+
failed_job_ids = SolidQueue::FailedExecution.where(job_id: job_ids).pluck(:job_id)
|
45
|
+
|
46
|
+
# Find all scheduled jobs in a single query
|
47
|
+
scheduled_job_ids = SolidQueue::ScheduledExecution.where(job_id: job_ids).pluck(:job_id)
|
48
|
+
|
49
|
+
# Attach the status information to each job
|
50
|
+
jobs.each do |job|
|
51
|
+
job.instance_variable_set(:@failed, failed_job_ids.include?(job.id))
|
52
|
+
job.instance_variable_set(:@scheduled, scheduled_job_ids.include?(job.id))
|
53
|
+
end
|
54
|
+
|
55
|
+
# Define the method to check if a job is failed
|
56
|
+
SolidQueue::Job.class_eval do
|
57
|
+
def failed?
|
58
|
+
if instance_variable_defined?(:@failed)
|
59
|
+
@failed
|
60
|
+
else
|
61
|
+
SolidQueue::FailedExecution.exists?(job_id: id)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def scheduled?
|
66
|
+
if instance_variable_defined?(:@scheduled)
|
67
|
+
@scheduled
|
68
|
+
else
|
69
|
+
SolidQueue::ScheduledExecution.exists?(job_id: id)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def filter_jobs(relation)
|
76
|
+
relation = relation.where('class_name LIKE ?', "%#{params[:class_name]}%") if params[:class_name].present?
|
77
|
+
relation = relation.where('queue_name LIKE ?', "%#{params[:queue_name]}%") if params[:queue_name].present?
|
78
|
+
relation = filter_by_arguments(relation) if params[:arguments].present?
|
79
|
+
|
80
|
+
if params[:status].present?
|
81
|
+
case params[:status]
|
82
|
+
when 'completed'
|
83
|
+
relation = relation.where.not(finished_at: nil)
|
84
|
+
when 'failed'
|
85
|
+
failed_job_ids = SolidQueue::FailedExecution.pluck(:job_id)
|
86
|
+
relation = relation.where(id: failed_job_ids)
|
87
|
+
when 'scheduled'
|
88
|
+
scheduled_job_ids = SolidQueue::ScheduledExecution.pluck(:job_id)
|
89
|
+
relation = relation.where(id: scheduled_job_ids)
|
90
|
+
when 'pending'
|
91
|
+
# Pending jobs are those that are not completed, failed, or scheduled
|
92
|
+
failed_job_ids = SolidQueue::FailedExecution.pluck(:job_id)
|
93
|
+
scheduled_job_ids = SolidQueue::ScheduledExecution.pluck(:job_id)
|
94
|
+
relation = relation.where(finished_at: nil)
|
95
|
+
.where.not(id: failed_job_ids + scheduled_job_ids)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
relation
|
100
|
+
end
|
101
|
+
|
102
|
+
def filter_by_arguments(relation)
|
103
|
+
# Use ILIKE for case-insensitive search in PostgreSQL
|
104
|
+
relation.where('arguments::text ILIKE ?', "%#{params[:arguments]}%")
|
105
|
+
end
|
106
|
+
|
107
|
+
def filter_ready_jobs(relation)
|
108
|
+
return relation unless params[:class_name].present? || params[:queue_name].present? || params[:arguments].present?
|
109
|
+
|
110
|
+
if params[:class_name].present?
|
111
|
+
job_ids = SolidQueue::Job.where('class_name LIKE ?', "%#{params[:class_name]}%").pluck(:id)
|
112
|
+
relation = relation.where(job_id: job_ids)
|
113
|
+
end
|
114
|
+
|
115
|
+
relation = relation.where('queue_name LIKE ?', "%#{params[:queue_name]}%") if params[:queue_name].present?
|
116
|
+
|
117
|
+
# Add arguments filtering
|
118
|
+
if params[:arguments].present?
|
119
|
+
job_ids = SolidQueue::Job.where('arguments::text ILIKE ?', "%#{params[:arguments]}%").pluck(:id)
|
120
|
+
relation = relation.where(job_id: job_ids)
|
121
|
+
end
|
122
|
+
|
123
|
+
relation
|
124
|
+
end
|
125
|
+
|
126
|
+
def filter_scheduled_jobs(relation)
|
127
|
+
return relation unless params[:class_name].present? || params[:queue_name].present? || params[:arguments].present?
|
128
|
+
|
129
|
+
if params[:class_name].present?
|
130
|
+
job_ids = SolidQueue::Job.where('class_name LIKE ?', "%#{params[:class_name]}%").pluck(:id)
|
131
|
+
relation = relation.where(job_id: job_ids)
|
132
|
+
end
|
133
|
+
|
134
|
+
relation = relation.where('queue_name LIKE ?', "%#{params[:queue_name]}%") if params[:queue_name].present?
|
135
|
+
|
136
|
+
# Add arguments filtering
|
137
|
+
if params[:arguments].present?
|
138
|
+
job_ids = SolidQueue::Job.where('arguments::text ILIKE ?', "%#{params[:arguments]}%").pluck(:id)
|
139
|
+
relation = relation.where(job_id: job_ids)
|
140
|
+
end
|
141
|
+
|
142
|
+
relation
|
143
|
+
end
|
144
|
+
|
145
|
+
def filter_recurring_jobs(relation)
|
146
|
+
return relation unless params[:class_name].present? || params[:queue_name].present? || params[:arguments].present?
|
147
|
+
|
148
|
+
relation = relation.where('class_name LIKE ?', "%#{params[:class_name]}%") if params[:class_name].present?
|
149
|
+
relation = relation.where('queue_name LIKE ?', "%#{params[:queue_name]}%") if params[:queue_name].present?
|
150
|
+
|
151
|
+
# Add arguments filtering if the model has arguments column
|
152
|
+
if params[:arguments].present? && relation.column_names.include?('arguments')
|
153
|
+
relation = relation.where('arguments::text ILIKE ?',
|
154
|
+
"%#{params[:arguments]}%")
|
155
|
+
end
|
156
|
+
|
157
|
+
relation
|
158
|
+
end
|
159
|
+
|
160
|
+
def filter_failed_jobs(relation)
|
161
|
+
return relation unless params[:class_name].present? || params[:queue_name].present? || params[:arguments].present?
|
162
|
+
|
163
|
+
if params[:class_name].present?
|
164
|
+
job_ids = SolidQueue::Job.where('class_name LIKE ?', "%#{params[:class_name]}%").pluck(:id)
|
165
|
+
relation = relation.where(job_id: job_ids)
|
166
|
+
end
|
167
|
+
|
168
|
+
if params[:queue_name].present?
|
169
|
+
# Check if FailedExecution has queue_name column
|
170
|
+
if relation.column_names.include?('queue_name')
|
171
|
+
relation = relation.where('queue_name LIKE ?', "%#{params[:queue_name]}%")
|
172
|
+
else
|
173
|
+
# If not, filter by job's queue_name
|
174
|
+
job_ids = SolidQueue::Job.where('queue_name LIKE ?', "%#{params[:queue_name]}%").pluck(:id)
|
175
|
+
relation = relation.where(job_id: job_ids)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# Add arguments filtering
|
180
|
+
if params[:arguments].present?
|
181
|
+
job_ids = SolidQueue::Job.where('arguments::text ILIKE ?', "%#{params[:arguments]}%").pluck(:id)
|
182
|
+
relation = relation.where(job_id: job_ids)
|
183
|
+
end
|
184
|
+
|
185
|
+
relation
|
186
|
+
end
|
187
|
+
|
188
|
+
def filter_params
|
189
|
+
{
|
190
|
+
class_name: params[:class_name],
|
191
|
+
queue_name: params[:queue_name],
|
192
|
+
arguments: params[:arguments],
|
193
|
+
status: params[:status]
|
194
|
+
}
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidQueueMonitor
|
4
|
+
class FailedJobsController < BaseController
|
5
|
+
def index
|
6
|
+
base_query = SolidQueue::FailedExecution.includes(:job).order(created_at: :desc)
|
7
|
+
@failed_jobs = paginate(filter_failed_jobs(base_query))
|
8
|
+
|
9
|
+
render_page('Failed Jobs', SolidQueueMonitor::FailedJobsPresenter.new(@failed_jobs[:records],
|
10
|
+
current_page: @failed_jobs[:current_page],
|
11
|
+
total_pages: @failed_jobs[:total_pages],
|
12
|
+
filters: filter_params).render)
|
13
|
+
end
|
14
|
+
|
15
|
+
def retry
|
16
|
+
id = params[:id]
|
17
|
+
service = SolidQueueMonitor::FailedJobService.new
|
18
|
+
|
19
|
+
if service.retry_job(id)
|
20
|
+
set_flash_message("Job #{id} has been queued for retry.", 'success')
|
21
|
+
else
|
22
|
+
set_flash_message("Failed to retry job #{id}.", 'error')
|
23
|
+
end
|
24
|
+
|
25
|
+
redirect_to(params[:redirect_to].presence || failed_jobs_path)
|
26
|
+
end
|
27
|
+
|
28
|
+
def discard
|
29
|
+
id = params[:id]
|
30
|
+
service = SolidQueueMonitor::FailedJobService.new
|
31
|
+
|
32
|
+
if service.discard_job(id)
|
33
|
+
set_flash_message("Job #{id} has been discarded.", 'success')
|
34
|
+
else
|
35
|
+
set_flash_message("Failed to discard job #{id}.", 'error')
|
36
|
+
end
|
37
|
+
|
38
|
+
redirect_to(params[:redirect_to].presence || failed_jobs_path)
|
39
|
+
end
|
40
|
+
|
41
|
+
def retry_all
|
42
|
+
result = SolidQueueMonitor::FailedJobService.new.retry_all(params[:job_ids])
|
43
|
+
|
44
|
+
if result[:success]
|
45
|
+
set_flash_message(result[:message], 'success')
|
46
|
+
else
|
47
|
+
set_flash_message(result[:message], 'error')
|
48
|
+
end
|
49
|
+
redirect_to failed_jobs_path
|
50
|
+
end
|
51
|
+
|
52
|
+
def discard_all
|
53
|
+
result = SolidQueueMonitor::FailedJobService.new.discard_all(params[:job_ids])
|
54
|
+
|
55
|
+
if result[:success]
|
56
|
+
set_flash_message(result[:message], 'success')
|
57
|
+
else
|
58
|
+
set_flash_message(result[:message], 'error')
|
59
|
+
end
|
60
|
+
redirect_to failed_jobs_path
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidQueueMonitor
|
4
|
+
class InProgressJobsController < BaseController
|
5
|
+
def index
|
6
|
+
base_query = SolidQueue::ClaimedExecution.includes(:job).order(created_at: :desc)
|
7
|
+
@in_progress_jobs = paginate(filter_in_progress_jobs(base_query))
|
8
|
+
|
9
|
+
render_page('In Progress Jobs', SolidQueueMonitor::InProgressJobsPresenter.new(@in_progress_jobs[:records],
|
10
|
+
current_page: @in_progress_jobs[:current_page],
|
11
|
+
total_pages: @in_progress_jobs[:total_pages],
|
12
|
+
filters: filter_params).render)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def filter_in_progress_jobs(relation)
|
18
|
+
return relation if params[:class_name].blank? && params[:arguments].blank?
|
19
|
+
|
20
|
+
if params[:class_name].present?
|
21
|
+
job_ids = SolidQueue::Job.where('class_name LIKE ?', "%#{params[:class_name]}%").pluck(:id)
|
22
|
+
relation = relation.where(job_id: job_ids)
|
23
|
+
end
|
24
|
+
|
25
|
+
if params[:arguments].present?
|
26
|
+
job_ids = SolidQueue::Job.where('arguments::text ILIKE ?', "%#{params[:arguments]}%").pluck(:id)
|
27
|
+
relation = relation.where(job_id: job_ids)
|
28
|
+
end
|
29
|
+
|
30
|
+
relation
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidQueueMonitor
|
4
|
+
class OverviewController < BaseController
|
5
|
+
def index
|
6
|
+
@stats = SolidQueueMonitor::StatsCalculator.calculate
|
7
|
+
|
8
|
+
recent_jobs_query = SolidQueue::Job.order(created_at: :desc).limit(100)
|
9
|
+
@recent_jobs = paginate(filter_jobs(recent_jobs_query))
|
10
|
+
|
11
|
+
preload_job_statuses(@recent_jobs[:records])
|
12
|
+
|
13
|
+
render_page('Overview', generate_overview_content)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def generate_overview_content
|
19
|
+
SolidQueueMonitor::StatsPresenter.new(@stats).render +
|
20
|
+
SolidQueueMonitor::JobsPresenter.new(@recent_jobs[:records],
|
21
|
+
current_page: @recent_jobs[:current_page],
|
22
|
+
total_pages: @recent_jobs[:total_pages],
|
23
|
+
filters: filter_params).render
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidQueueMonitor
|
4
|
+
class QueuesController < BaseController
|
5
|
+
def index
|
6
|
+
@queues = SolidQueue::Job.group(:queue_name)
|
7
|
+
.select('queue_name, COUNT(*) as job_count')
|
8
|
+
.order('job_count DESC')
|
9
|
+
|
10
|
+
render_page('Queues', SolidQueueMonitor::QueuesPresenter.new(@queues).render)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidQueueMonitor
|
4
|
+
class ReadyJobsController < BaseController
|
5
|
+
def index
|
6
|
+
base_query = SolidQueue::ReadyExecution.includes(:job).order(created_at: :desc)
|
7
|
+
@ready_jobs = paginate(filter_ready_jobs(base_query))
|
8
|
+
|
9
|
+
render_page('Ready Jobs', SolidQueueMonitor::ReadyJobsPresenter.new(@ready_jobs[:records],
|
10
|
+
current_page: @ready_jobs[:current_page],
|
11
|
+
total_pages: @ready_jobs[:total_pages],
|
12
|
+
filters: filter_params).render)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidQueueMonitor
|
4
|
+
class RecurringJobsController < BaseController
|
5
|
+
def index
|
6
|
+
base_query = filter_recurring_jobs(SolidQueue::RecurringTask.order(:key))
|
7
|
+
@recurring_jobs = paginate(base_query)
|
8
|
+
|
9
|
+
render_page('Recurring Jobs', SolidQueueMonitor::RecurringJobsPresenter.new(@recurring_jobs[:records],
|
10
|
+
current_page: @recurring_jobs[:current_page],
|
11
|
+
total_pages: @recurring_jobs[:total_pages],
|
12
|
+
filters: filter_params).render)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidQueueMonitor
|
4
|
+
class ScheduledJobsController < BaseController
|
5
|
+
def index
|
6
|
+
base_query = SolidQueue::ScheduledExecution.includes(:job).order(scheduled_at: :asc)
|
7
|
+
@scheduled_jobs = paginate(filter_scheduled_jobs(base_query))
|
8
|
+
|
9
|
+
render_page('Scheduled Jobs', SolidQueueMonitor::ScheduledJobsPresenter.new(@scheduled_jobs[:records],
|
10
|
+
current_page: @scheduled_jobs[:current_page],
|
11
|
+
total_pages: @scheduled_jobs[:total_pages],
|
12
|
+
filters: filter_params).render)
|
13
|
+
end
|
14
|
+
|
15
|
+
def create
|
16
|
+
if params[:job_ids].present?
|
17
|
+
SolidQueueMonitor::ExecuteJobService.new.execute_many(params[:job_ids])
|
18
|
+
set_flash_message('Selected jobs moved to ready queue', 'success')
|
19
|
+
else
|
20
|
+
set_flash_message('No jobs selected', 'error')
|
21
|
+
end
|
22
|
+
redirect_to scheduled_jobs_path
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|