sidekiq_queue_manager 1.0.1 → 1.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.
@@ -30,6 +30,21 @@
30
30
  <div class="sqm-stat-label">Enqueued Jobs</div>
31
31
  <div class="sqm-stat-value" id="sqm-enqueued">0</div>
32
32
  </div>
33
+
34
+ <div class="sqm-stat-card">
35
+ <div class="sqm-stat-label">Scheduled Jobs</div>
36
+ <div class="sqm-stat-value" id="sqm-scheduled-jobs">0</div>
37
+ </div>
38
+
39
+ <div class="sqm-stat-card">
40
+ <div class="sqm-stat-label">Retry Jobs</div>
41
+ <div class="sqm-stat-value" id="sqm-retry-jobs">0</div>
42
+ </div>
43
+
44
+ <div class="sqm-stat-card">
45
+ <div class="sqm-stat-label">Dead Jobs</div>
46
+ <div class="sqm-stat-value" id="sqm-dead-jobs">0</div>
47
+ </div>
33
48
  </div>
34
49
  </section>
35
50
 
@@ -134,25 +149,278 @@
134
149
 
135
150
  <!-- Main Content -->
136
151
  <div id="sqm-content" class="sqm-hidden">
137
- <!-- Queues Table -->
138
- <section class="sqm-queues-section" aria-label="Queue Details">
139
- <div class="sqm-table-container">
140
- <table class="sqm-table" id="sqm-queues-table">
141
- <thead>
142
- <tr>
143
- <th scope="col">Queue Name</th>
144
- <th scope="col" style="text-align: right;">Size</th>
145
- <th scope="col" style="text-align: right;">Workers/Limits</th>
146
- <th scope="col" style="text-align: right;">Latency</th>
147
- <th scope="col" style="text-align: right;">Actions</th>
148
- </tr>
149
- </thead>
150
- <tbody id="sqm-table-body">
151
- <!-- Queue rows will be inserted here by JavaScript -->
152
- </tbody>
153
- </table>
154
- </div>
155
- </section>
152
+ <!-- Navigation Tabs -->
153
+ <nav class="sqm-tabs-nav" role="tablist" aria-label="Job management sections">
154
+ <button
155
+ class="sqm-tab sqm-tab-active"
156
+ role="tab"
157
+ aria-selected="true"
158
+ aria-controls="sqm-queues-panel"
159
+ id="sqm-queues-tab"
160
+ data-tab="queues">
161
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" style="width: 1rem; height: 1rem;">
162
+ <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5M12 17.25h8.25M3.75 17.25h.01v.01h-.01v-.01ZM7.5 17.25h.01v.01H7.5v-.01ZM11.25 17.25h.01v.01h-.01v-.01Z" />
163
+ </svg>
164
+ Queues
165
+ <span class="sqm-tab-count" id="sqm-queues-count">0</span>
166
+ </button>
167
+
168
+ <button
169
+ class="sqm-tab"
170
+ role="tab"
171
+ aria-selected="false"
172
+ aria-controls="sqm-scheduled-panel"
173
+ id="sqm-scheduled-tab"
174
+ data-tab="scheduled">
175
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" style="width: 1rem; height: 1rem;">
176
+ <path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z" />
177
+ </svg>
178
+ Scheduled
179
+ <span class="sqm-tab-count" id="sqm-scheduled-count">0</span>
180
+ </button>
181
+
182
+ <button
183
+ class="sqm-tab"
184
+ role="tab"
185
+ aria-selected="false"
186
+ aria-controls="sqm-retries-panel"
187
+ id="sqm-retries-tab"
188
+ data-tab="retries">
189
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" style="width: 1rem; height: 1rem;">
190
+ <path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99" />
191
+ </svg>
192
+ Retries
193
+ <span class="sqm-tab-count" id="sqm-retries-count">0</span>
194
+ </button>
195
+
196
+ <button
197
+ class="sqm-tab"
198
+ role="tab"
199
+ aria-selected="false"
200
+ aria-controls="sqm-dead-panel"
201
+ id="sqm-dead-tab"
202
+ data-tab="dead">
203
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" style="width: 1rem; height: 1rem;">
204
+ <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" />
205
+ </svg>
206
+ Dead
207
+ <span class="sqm-tab-count" id="sqm-dead-count">0</span>
208
+ </button>
209
+ </nav>
210
+
211
+ <!-- Tab Panels -->
212
+ <div class="sqm-tab-content">
213
+ <!-- Queues Panel -->
214
+ <div
215
+ class="sqm-tab-panel sqm-tab-panel-active"
216
+ role="tabpanel"
217
+ aria-labelledby="sqm-queues-tab"
218
+ id="sqm-queues-panel">
219
+ <section class="sqm-queues-section" aria-label="Queue Details">
220
+ <div class="sqm-table-container">
221
+ <table class="sqm-table" id="sqm-queues-table">
222
+ <thead>
223
+ <tr>
224
+ <th scope="col">Queue Name</th>
225
+ <th scope="col" style="text-align: right;">Size</th>
226
+ <th scope="col" style="text-align: right;">Workers/Limits</th>
227
+ <th scope="col" style="text-align: right;">Latency</th>
228
+ <th scope="col" style="text-align: right;">Actions</th>
229
+ </tr>
230
+ </thead>
231
+ <tbody id="sqm-table-body">
232
+ <!-- Queue rows will be inserted here by JavaScript -->
233
+ </tbody>
234
+ </table>
235
+ </div>
236
+ </section>
237
+ </div>
238
+
239
+ <!-- Scheduled Jobs Panel -->
240
+ <div
241
+ class="sqm-tab-panel sqm-hidden"
242
+ role="tabpanel"
243
+ aria-labelledby="sqm-scheduled-tab"
244
+ id="sqm-scheduled-panel">
245
+ <section class="sqm-scheduled-section" aria-label="Scheduled Jobs">
246
+ <!-- Scheduled Jobs Controls -->
247
+ <div class="sqm-section-controls">
248
+ <div class="sqm-controls-left">
249
+ <input
250
+ type="text"
251
+ id="sqm-scheduled-filter"
252
+ class="sqm-filter-input"
253
+ placeholder="Filter by job class..."
254
+ aria-label="Filter scheduled jobs">
255
+ <button id="sqm-scheduled-apply-filter" class="sqm-btn sqm-btn-secondary">
256
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" style="width: 1rem; height: 1rem;">
257
+ <path stroke-linecap="round" stroke-linejoin="round" d="M12 3c2.755 0 5.455.232 8.083.678.533.09.917.556.917 1.096v1.044a2.25 2.25 0 01-.659 1.591l-5.432 5.432a2.25 2.25 0 00-.659 1.591v2.927a2.25 2.25 0 01-1.244 2.013L9.75 21v-6.568a2.25 2.25 0 00-.659-1.591L3.659 7.409A2.25 2.25 0 013 5.818V4.774c0-.54.384-1.006.917-1.096A48.32 48.32 0 0112 3z" />
258
+ </svg>
259
+ Filter
260
+ </button>
261
+ </div>
262
+ <div class="sqm-controls-right">
263
+ <button id="sqm-clear-scheduled-btn" class="sqm-btn sqm-btn-destructive">
264
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" style="width: 1rem; height: 1rem;">
265
+ <path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" />
266
+ </svg>
267
+ Clear All
268
+ </button>
269
+ </div>
270
+ </div>
271
+
272
+ <div class="sqm-table-container">
273
+ <table class="sqm-table" id="sqm-scheduled-table">
274
+ <thead>
275
+ <tr>
276
+ <th scope="col">Job Class</th>
277
+ <th scope="col">Queue</th>
278
+ <th scope="col" style="text-align: right;">Scheduled At</th>
279
+ <th scope="col" style="text-align: right;">Time Until</th>
280
+ <th scope="col" style="text-align: right;">Actions</th>
281
+ </tr>
282
+ </thead>
283
+ <tbody id="sqm-scheduled-table-body">
284
+ <!-- Scheduled job rows will be inserted here by JavaScript -->
285
+ </tbody>
286
+ </table>
287
+ </div>
288
+
289
+ <!-- Pagination -->
290
+ <div class="sqm-pagination" id="sqm-scheduled-pagination">
291
+ <!-- Pagination controls will be inserted here by JavaScript -->
292
+ </div>
293
+ </section>
294
+ </div>
295
+
296
+ <!-- Retry Jobs Panel -->
297
+ <div
298
+ class="sqm-tab-panel sqm-hidden"
299
+ role="tabpanel"
300
+ aria-labelledby="sqm-retries-tab"
301
+ id="sqm-retries-panel">
302
+ <section class="sqm-retries-section" aria-label="Retry Jobs">
303
+ <!-- Retry Jobs Controls -->
304
+ <div class="sqm-section-controls">
305
+ <div class="sqm-controls-left">
306
+ <input
307
+ type="text"
308
+ id="sqm-retries-filter"
309
+ class="sqm-filter-input"
310
+ placeholder="Filter by job class..."
311
+ aria-label="Filter retry jobs">
312
+ <button id="sqm-retries-apply-filter" class="sqm-btn sqm-btn-secondary">
313
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" style="width: 1rem; height: 1rem;">
314
+ <path stroke-linecap="round" stroke-linejoin="round" d="M12 3c2.755 0 5.455.232 8.083.678.533.09.917.556.917 1.096v1.044a2.25 2.25 0 01-.659 1.591l-5.432 5.432a2.25 2.25 0 00-.659 1.591v2.927a2.25 2.25 0 01-1.244 2.013L9.75 21v-6.568a2.25 2.25 0 00-.659-1.591L3.659 7.409A2.25 2.25 0 013 5.818V4.774c0-.54.384-1.006.917-1.096A48.32 48.32 0 0112 3z" />
315
+ </svg>
316
+ Filter
317
+ </button>
318
+ </div>
319
+ <div class="sqm-controls-right">
320
+ <button id="sqm-retry-all-btn" class="sqm-btn sqm-btn-success">
321
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" style="width: 1rem; height: 1rem;">
322
+ <path stroke-linecap="round" stroke-linejoin="round" d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.348a1.125 1.125 0 010 1.971l-11.54 6.347a1.125 1.125 0 01-1.667-.985V5.653z" />
323
+ </svg>
324
+ Retry All
325
+ </button>
326
+ <button id="sqm-clear-retries-btn" class="sqm-btn sqm-btn-destructive">
327
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" style="width: 1rem; height: 1rem;">
328
+ <path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" />
329
+ </svg>
330
+ Clear All
331
+ </button>
332
+ </div>
333
+ </div>
334
+
335
+ <div class="sqm-table-container">
336
+ <table class="sqm-table" id="sqm-retries-table">
337
+ <thead>
338
+ <tr>
339
+ <th scope="col">Job Class</th>
340
+ <th scope="col">Queue</th>
341
+ <th scope="col" style="text-align: right;">Failed At</th>
342
+ <th scope="col" style="text-align: right;">Retry At</th>
343
+ <th scope="col" style="text-align: right;">Attempts</th>
344
+ <th scope="col" style="text-align: right;">Actions</th>
345
+ </tr>
346
+ </thead>
347
+ <tbody id="sqm-retries-table-body">
348
+ <!-- Retry job rows will be inserted here by JavaScript -->
349
+ </tbody>
350
+ </table>
351
+ </div>
352
+
353
+ <!-- Pagination -->
354
+ <div class="sqm-pagination" id="sqm-retries-pagination">
355
+ <!-- Pagination controls will be inserted here by JavaScript -->
356
+ </div>
357
+ </section>
358
+ </div>
359
+
360
+ <!-- Dead Jobs Panel -->
361
+ <div
362
+ class="sqm-tab-panel sqm-hidden"
363
+ role="tabpanel"
364
+ aria-labelledby="sqm-dead-tab"
365
+ id="sqm-dead-panel">
366
+ <section class="sqm-dead-section" aria-label="Dead Jobs">
367
+ <!-- Dead Jobs Controls -->
368
+ <div class="sqm-section-controls">
369
+ <div class="sqm-controls-left">
370
+ <input
371
+ type="text"
372
+ id="sqm-dead-filter"
373
+ class="sqm-filter-input"
374
+ placeholder="Filter by job class..."
375
+ aria-label="Filter dead jobs">
376
+ <button id="sqm-dead-apply-filter" class="sqm-btn sqm-btn-secondary">
377
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" style="width: 1rem; height: 1rem;">
378
+ <path stroke-linecap="round" stroke-linejoin="round" d="M12 3c2.755 0 5.455.232 8.083.678.533.09.917.556.917 1.096v1.044a2.25 2.25 0 01-.659 1.591l-5.432 5.432a2.25 2.25 0 00-.659 1.591v2.927a2.25 2.25 0 01-1.244 2.013L9.75 21v-6.568a2.25 2.25 0 00-.659-1.591L3.659 7.409A2.25 2.25 0 013 5.818V4.774c0-.54.384-1.006.917-1.096A48.32 48.32 0 0112 3z" />
379
+ </svg>
380
+ Filter
381
+ </button>
382
+ </div>
383
+ <div class="sqm-controls-right">
384
+ <button id="sqm-resurrect-all-btn" class="sqm-btn sqm-btn-info">
385
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" style="width: 1rem; height: 1rem;">
386
+ <path stroke-linecap="round" stroke-linejoin="round" d="M15.59 14.37a6 6 0 01-5.84 7.38v-4.8m5.84-2.58a14.98 14.98 0 006.16-12.12A14.98 14.98 0 009.631 8.41m5.96 5.96a14.926 14.926 0 01-5.841 2.58m-.119-8.54a6 6 0 00-7.381 5.84h4.8m2.581-5.84a14.927 14.927 0 00-2.58 5.84m2.699 2.7c-.103-.212-.202-.426-.297-.642m-.838 2.956c.138-.78.404-1.476.804-2.031a4.73 4.73 0 01.945-1.067m.02 2.4a5.54 5.54 0 01-.72.01" />
387
+ </svg>
388
+ Resurrect All
389
+ </button>
390
+ <button id="sqm-clear-dead-btn" class="sqm-btn sqm-btn-destructive">
391
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" style="width: 1rem; height: 1rem;">
392
+ <path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" />
393
+ </svg>
394
+ Clear All
395
+ </button>
396
+ </div>
397
+ </div>
398
+
399
+ <div class="sqm-table-container">
400
+ <table class="sqm-table" id="sqm-dead-table">
401
+ <thead>
402
+ <tr>
403
+ <th scope="col">Job Class</th>
404
+ <th scope="col">Queue</th>
405
+ <th scope="col" style="text-align: right;">Failed At</th>
406
+ <th scope="col" style="text-align: right;">Attempts</th>
407
+ <th scope="col" style="text-align: right;">Error</th>
408
+ <th scope="col" style="text-align: right;">Actions</th>
409
+ </tr>
410
+ </thead>
411
+ <tbody id="sqm-dead-table-body">
412
+ <!-- Dead job rows will be inserted here by JavaScript -->
413
+ </tbody>
414
+ </table>
415
+ </div>
416
+
417
+ <!-- Pagination -->
418
+ <div class="sqm-pagination" id="sqm-dead-pagination">
419
+ <!-- Pagination controls will be inserted here by JavaScript -->
420
+ </div>
421
+ </section>
422
+ </div>
423
+ </div>
156
424
  </div>
157
425
 
158
426
  <!-- Empty State (when no queues) -->
data/config/routes.rb CHANGED
@@ -24,6 +24,27 @@ SidekiqQueueManager::Engine.routes.draw do
24
24
  post '/queues/resume_all', to: 'dashboard#resume_all', as: :resume_all_queues
25
25
  get '/queues/summary', to: 'dashboard#summary', as: :queues_summary
26
26
 
27
+ # Scheduled jobs management
28
+ get '/scheduled', to: 'dashboard#scheduled_jobs', as: :scheduled_jobs
29
+ delete '/scheduled/:id', to: 'dashboard#delete_scheduled_job', as: :delete_scheduled_job
30
+ post '/scheduled/:id/enqueue', to: 'dashboard#enqueue_scheduled_job', as: :enqueue_scheduled_job
31
+ post '/scheduled/clear', to: 'dashboard#clear_scheduled_jobs', as: :clear_scheduled_jobs
32
+
33
+ # Retry jobs management
34
+ get '/retries', to: 'dashboard#retry_jobs', as: :retry_jobs
35
+ post '/retries/:id/retry', to: 'dashboard#retry_job_now', as: :retry_job_now
36
+ delete '/retries/:id', to: 'dashboard#delete_retry_job', as: :delete_retry_job
37
+ post '/retries/:id/kill', to: 'dashboard#kill_retry_job', as: :kill_retry_job
38
+ post '/retries/clear', to: 'dashboard#clear_retry_jobs', as: :clear_retry_jobs
39
+ post '/retries/retry_all', to: 'dashboard#retry_all_jobs', as: :retry_all_jobs
40
+
41
+ # Dead jobs management
42
+ get '/dead', to: 'dashboard#dead_jobs', as: :dead_jobs
43
+ post '/dead/:id/resurrect', to: 'dashboard#resurrect_dead_job', as: :resurrect_dead_job
44
+ delete '/dead/:id', to: 'dashboard#delete_dead_job', as: :delete_dead_job
45
+ post '/dead/clear', to: 'dashboard#clear_dead_jobs', as: :clear_dead_jobs
46
+ post '/dead/resurrect_all', to: 'dashboard#resurrect_all_dead_jobs', as: :resurrect_all_dead_jobs
47
+
27
48
  # Individual queue operations
28
49
  post '/queues/:name/pause', to: 'dashboard#pause_queue', as: :pause_queue
29
50
  post '/queues/:name/resume', to: 'dashboard#resume_queue', as: :resume_queue
@@ -135,7 +135,18 @@ module SidekiqQueueManager
135
135
 
136
136
  def configure_sidekiq_server_options
137
137
  Sidekiq.configure_server do |config|
138
- config.options[:fetch] = Sidekiq::LimitFetch
138
+ # Sidekiq 7.x+ removed config.options API, check if sidekiq-limit_fetch
139
+ # supports the new configuration method
140
+ if config.respond_to?(:options) && config.options.respond_to?(:[]=)
141
+ # Sidekiq 6.x and earlier
142
+ config.options[:fetch] = Sidekiq::LimitFetch
143
+ else
144
+ # Sidekiq 7.x+ - sidekiq-limit_fetch may need different configuration
145
+ # or may not be compatible. Log a warning for now.
146
+ Rails.logger.warn "[SidekiqQueueManager] sidekiq-limit_fetch configuration skipped - " \
147
+ "may not be compatible with Sidekiq #{Sidekiq::VERSION}"
148
+ Rails.logger.warn '[SidekiqQueueManager] Queue limits may not work as expected'
149
+ end
139
150
  end
140
151
  end
141
152
 
@@ -7,6 +7,6 @@ module SidekiqQueueManager
7
7
  # - MAJOR: Incompatible API changes
8
8
  # - MINOR: Add functionality in backward compatible manner
9
9
  # - PATCH: Backward compatible bug fixes
10
- VERSION = '1.0.1'
10
+ VERSION = '1.1.0'
11
11
  end
12
12
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq_queue_manager
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamal Awad