solid_queue_monitor 0.1.0 → 0.1.2

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.
@@ -37,21 +37,24 @@ module SolidQueueMonitor
37
37
  </div>
38
38
  </form>
39
39
  </div>
40
+
41
+ <div class="bulk-actions-bar">
42
+ <button type="button" class="action-button execute-button" id="execute-selected-top" disabled>Execute Selected</button>
43
+ </div>
40
44
  HTML
41
45
  end
42
46
 
43
47
  def generate_table_with_actions
44
48
  <<-HTML
45
- <form action="#{execute_jobs_path}" method="POST">
49
+ <form id="scheduled-jobs-form" action="#{execute_jobs_path}" method="POST">
46
50
  #{generate_table}
47
- <div class="table-actions">
48
- <button type="submit" class="execute-btn" id="bulk-execute" disabled>Execute Selected</button>
49
- </div>
50
51
  </form>
51
52
  <script>
52
53
  document.addEventListener('DOMContentLoaded', function() {
53
54
  const selectAllCheckbox = document.querySelector('th input[type="checkbox"]');
54
55
  const jobCheckboxes = document.getElementsByName('job_ids[]');
56
+ const executeButton = document.getElementById('execute-selected-top');
57
+ const form = document.getElementById('scheduled-jobs-form');
55
58
 
56
59
  selectAllCheckbox.addEventListener('change', function() {
57
60
  jobCheckboxes.forEach(checkbox => checkbox.checked = this.checked);
@@ -64,13 +67,33 @@ module SolidQueueMonitor
64
67
  updateExecuteButton();
65
68
  });
66
69
  });
70
+
71
+ // Add event listener for the execute button
72
+ executeButton.addEventListener('click', function() {
73
+ const selectedIds = Array.from(document.querySelectorAll('input[name="job_ids[]"]:checked')).map(cb => cb.value);
74
+ if (selectedIds.length === 0) return;
75
+
76
+ // Add selected IDs as hidden inputs
77
+ selectedIds.forEach(id => {
78
+ const input = document.createElement('input');
79
+ input.type = 'hidden';
80
+ input.name = 'job_ids[]';
81
+ input.value = id;
82
+ form.appendChild(input);
83
+ });
84
+
85
+ form.submit();
86
+ });
87
+
88
+ function updateExecuteButton() {
89
+ const checkboxes = document.getElementsByName('job_ids[]');
90
+ const checked = Array.from(checkboxes).some(cb => cb.checked);
91
+ executeButton.disabled = !checked;
92
+ }
93
+
94
+ // Initialize button state
95
+ updateExecuteButton();
67
96
  });
68
-
69
- function updateExecuteButton() {
70
- const checkboxes = document.getElementsByName('job_ids[]');
71
- const checked = Array.from(checkboxes).some(cb => cb.checked);
72
- document.getElementById('bulk-execute').disabled = !checked;
73
- }
74
97
  </script>
75
98
  HTML
76
99
  end
@@ -0,0 +1,103 @@
1
+ module SolidQueueMonitor
2
+ class FailedJobService
3
+ def retry_job(failed_execution_id)
4
+ failed_execution = SolidQueue::FailedExecution.find_by(id: failed_execution_id)
5
+ return { success: false, message: "Failed job not found" } unless failed_execution
6
+
7
+ job = failed_execution.job
8
+ return { success: false, message: "Associated job not found" } unless job
9
+
10
+ ActiveRecord::Base.transaction do
11
+ # Create a ready execution for the job
12
+ SolidQueue::ReadyExecution.create!(
13
+ job_id: job.id,
14
+ queue_name: get_queue_name(failed_execution, job),
15
+ priority: job.priority
16
+ )
17
+
18
+ # Delete the failed execution
19
+ failed_execution.destroy!
20
+ end
21
+
22
+ { success: true, message: "Job moved to ready queue for retry" }
23
+ end
24
+
25
+ def discard_job(failed_execution_id)
26
+ failed_execution = SolidQueue::FailedExecution.find_by(id: failed_execution_id)
27
+ return { success: false, message: "Failed job not found" } unless failed_execution
28
+
29
+ job = failed_execution.job
30
+ return { success: false, message: "Associated job not found" } unless job
31
+
32
+ ActiveRecord::Base.transaction do
33
+ # Mark the job as finished
34
+ job.update!(finished_at: Time.current)
35
+
36
+ # Delete the failed execution
37
+ failed_execution.destroy!
38
+ end
39
+
40
+ { success: true, message: "Job has been discarded" }
41
+ end
42
+
43
+ def retry_all(job_ids)
44
+ return { success: false, message: "No jobs selected" } if job_ids.blank?
45
+
46
+ success_count = 0
47
+ failed_count = 0
48
+
49
+ job_ids.each do |id|
50
+ result = retry_job(id)
51
+ if result[:success]
52
+ success_count += 1
53
+ else
54
+ failed_count += 1
55
+ end
56
+ end
57
+
58
+ if success_count > 0 && failed_count == 0
59
+ { success: true, message: "All selected jobs have been queued for retry" }
60
+ elsif success_count > 0 && failed_count > 0
61
+ { success: true, message: "#{success_count} jobs queued for retry, #{failed_count} failed" }
62
+ else
63
+ { success: false, message: "Failed to retry jobs" }
64
+ end
65
+ end
66
+
67
+ def discard_all(job_ids)
68
+ return { success: false, message: "No jobs selected" } if job_ids.blank?
69
+
70
+ success_count = 0
71
+ failed_count = 0
72
+
73
+ job_ids.each do |id|
74
+ result = discard_job(id)
75
+ if result[:success]
76
+ success_count += 1
77
+ else
78
+ failed_count += 1
79
+ end
80
+ end
81
+
82
+ if success_count > 0 && failed_count == 0
83
+ { success: true, message: "All selected jobs have been discarded" }
84
+ elsif success_count > 0 && failed_count > 0
85
+ { success: true, message: "#{success_count} jobs discarded, #{failed_count} failed" }
86
+ else
87
+ { success: false, message: "Failed to discard jobs" }
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ def get_queue_name(failed_execution, job)
94
+ # Try to get queue_name from failed_execution if the method exists
95
+ if failed_execution.respond_to?(:queue_name) && failed_execution.queue_name.present?
96
+ failed_execution.queue_name
97
+ else
98
+ # Fall back to job's queue_name
99
+ job.queue_name
100
+ end
101
+ end
102
+ end
103
+ end
@@ -18,7 +18,7 @@ module SolidQueueMonitor
18
18
  <title>Solid Queue Monitor - #{@title}</title>
19
19
  #{generate_head}
20
20
  </head>
21
- <body>
21
+ <body class="solid_queue_monitor">
22
22
  #{generate_body}
23
23
  </body>
24
24
  </html>
@@ -54,7 +54,32 @@ module SolidQueueMonitor
54
54
  def render_message
55
55
  return '' unless @message
56
56
  class_name = @message_type == 'success' ? 'message-success' : 'message-error'
57
- "<div class='message #{class_name}'>#{@message}</div>"
57
+ <<-HTML
58
+ <div id="flash-message" class="message #{class_name}">#{@message}</div>
59
+ <script>
60
+ // Automatically hide the flash message after 5 seconds
61
+ document.addEventListener('DOMContentLoaded', function() {
62
+ var flashMessage = document.getElementById('flash-message');
63
+ if (flashMessage) {
64
+ setTimeout(function() {
65
+ flashMessage.style.opacity = '1';
66
+ // Fade out animation
67
+ var fadeEffect = setInterval(function() {
68
+ if (!flashMessage.style.opacity) {
69
+ flashMessage.style.opacity = 1;
70
+ }
71
+ if (flashMessage.style.opacity > 0) {
72
+ flashMessage.style.opacity -= 0.1;
73
+ } else {
74
+ clearInterval(fadeEffect);
75
+ flashMessage.style.display = 'none';
76
+ }
77
+ }, 50);
78
+ }, 5000); // 5 seconds
79
+ }
80
+ });
81
+ </script>
82
+ HTML
58
83
  end
59
84
 
60
85
  def generate_header