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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +25 -11
  3. data/Rakefile +8 -8
  4. data/app/controllers/solid_queue_monitor/application_controller.rb +25 -0
  5. data/app/controllers/solid_queue_monitor/base_controller.rb +197 -0
  6. data/app/controllers/solid_queue_monitor/failed_jobs_controller.rb +63 -0
  7. data/app/controllers/solid_queue_monitor/in_progress_jobs_controller.rb +33 -0
  8. data/app/controllers/solid_queue_monitor/overview_controller.rb +26 -0
  9. data/app/controllers/solid_queue_monitor/queues_controller.rb +13 -0
  10. data/app/controllers/solid_queue_monitor/ready_jobs_controller.rb +15 -0
  11. data/app/controllers/solid_queue_monitor/recurring_jobs_controller.rb +15 -0
  12. data/app/controllers/solid_queue_monitor/scheduled_jobs_controller.rb +25 -0
  13. data/app/presenters/solid_queue_monitor/base_presenter.rb +44 -39
  14. data/app/presenters/solid_queue_monitor/failed_jobs_presenter.rb +51 -45
  15. data/app/presenters/solid_queue_monitor/in_progress_jobs_presenter.rb +82 -0
  16. data/app/presenters/solid_queue_monitor/jobs_presenter.rb +46 -3
  17. data/app/presenters/solid_queue_monitor/queues_presenter.rb +5 -5
  18. data/app/presenters/solid_queue_monitor/ready_jobs_presenter.rb +10 -2
  19. data/app/presenters/solid_queue_monitor/recurring_jobs_presenter.rb +5 -2
  20. data/app/presenters/solid_queue_monitor/scheduled_jobs_presenter.rb +15 -9
  21. data/app/presenters/solid_queue_monitor/stats_presenter.rb +5 -3
  22. data/app/services/solid_queue_monitor/authentication_service.rb +7 -5
  23. data/app/services/solid_queue_monitor/execute_job_service.rb +3 -1
  24. data/app/services/solid_queue_monitor/failed_job_service.rb +38 -42
  25. data/app/services/solid_queue_monitor/html_generator.rb +7 -3
  26. data/app/services/solid_queue_monitor/pagination_service.rb +3 -1
  27. data/app/services/solid_queue_monitor/stats_calculator.rb +4 -1
  28. data/app/services/solid_queue_monitor/status_calculator.rb +4 -1
  29. data/app/services/solid_queue_monitor/stylesheet_generator.rb +23 -21
  30. data/config/initializers/solid_queue_monitor.rb +3 -1
  31. data/config/routes.rb +18 -16
  32. data/lib/generators/solid_queue_monitor/install_generator.rb +7 -5
  33. data/lib/generators/solid_queue_monitor/templates/initializer.rb +3 -1
  34. data/lib/solid_queue_monitor/engine.rb +5 -3
  35. data/lib/solid_queue_monitor/version.rb +1 -1
  36. data/lib/solid_queue_monitor.rb +9 -13
  37. data/lib/tasks/app.rake +42 -40
  38. metadata +18 -148
  39. 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: 1cadc5702b1a5de9167c64a48abfb6639362a3d4e765a3fb1bdf250f5ed4fa81
4
- data.tar.gz: 9f76e05408872948070221edb908146e134bbf67d6be1bc5fe8e8cbbd6b181ea
3
+ metadata.gz: d2911139409c2a387a2c425c0ef9927071a05dcf5f718e5aefc7bfb86cc4b7b6
4
+ data.tar.gz: 398de34669f64b9d4cab2cf1ed7e1f19da6fcd56b67df8da2c2682410308a905
5
5
  SHA512:
6
- metadata.gz: c27275ffbfc1c18e3c790abe1c6776f417af6c8684ffd33e392ae94dccb022b6465fe4754154aec86e6c2690f77e5ec674cf77893ce71c34e40a71498d9364e7
7
- data.tar.gz: ebb05f940720c5f10aab733f2632584d274af3c786300ba56d9f208535610d5034bbd3b0e8554d55e9f2244e4c6a460f646ef68ad533f03edab038264d7c2c12
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 job queue with statistics and counts
19
- - **Job Filtering**: Filter jobs by class name, queue name, and status
20
- - **Job Management**: Execute scheduled jobs on demand
21
- - **Failed Job Inspection**: View detailed error information for failed jobs
22
- - **Queue Monitoring**: Track job distribution across different queues
23
- - **Recurring Jobs**: Monitor and manage recurring background tasks
24
- - **Pagination**: Navigate through large job lists with ease
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
- ![Dashboard Overview](screenshots/dashboard.png)
36
+ ![Dashboard Overview](screenshots/dashboard-2.png)
34
37
 
35
- ### Recurring Jobs
38
+ ### Failed Jobs
36
39
 
37
- ![Recurring Jobs](screenshots/recurring_jobs.png)
40
+ ![Failed Jobs](screenshots/failed_jobs.png)
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.1.2'
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 "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
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 :setup do
11
+ task setup: :environment do
12
12
  require 'fileutils'
13
13
  FileUtils.mkdir_p 'spec/dummy/db'
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")
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 :prepare_test_env do
20
- Rake::Task["db:setup"].invoke
19
+ task prepare_test_env: :environment do
20
+ Rake::Task['db:setup'].invoke
21
21
  end
22
22
 
23
- task :spec => :prepare_test_env
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