good_job 4.4.2 → 4.5.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/CHANGELOG.md +32 -0
- data/app/controllers/good_job/cleaner_controller.rb +37 -0
- data/app/controllers/good_job/metrics_controller.rb +2 -0
- data/app/filters/good_job/base_filter.rb +1 -0
- data/app/filters/good_job/jobs_filter.rb +18 -2
- data/app/models/good_job/job.rb +6 -1
- data/app/models/good_job/process.rb +31 -1
- data/app/views/good_job/batches/_jobs.erb +5 -4
- data/app/views/good_job/cleaner/index.html.erb +85 -0
- data/app/views/good_job/jobs/_table.erb +3 -2
- data/app/views/good_job/processes/index.html.erb +1 -0
- data/app/views/good_job/shared/_navbar.erb +6 -0
- data/config/brakeman.ignore +26 -3
- data/config/locales/de.yml +15 -0
- data/config/locales/en.yml +15 -0
- data/config/locales/es.yml +15 -0
- data/config/locales/fr.yml +15 -0
- data/config/locales/it.yml +15 -0
- data/config/locales/ja.yml +15 -0
- data/config/locales/ko.yml +15 -0
- data/config/locales/nl.yml +15 -0
- data/config/locales/pt-BR.yml +15 -0
- data/config/locales/ru.yml +15 -0
- data/config/locales/tr.yml +15 -0
- data/config/locales/uk.yml +15 -0
- data/config/routes.rb +1 -1
- data/lib/good_job/capsule_tracker.rb +1 -1
- data/lib/good_job/cron_manager.rb +24 -12
- data/lib/good_job/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3f0a8926625f33b36c56def63a1507cfb0f8981a876449e907396aa2338b0b78
|
4
|
+
data.tar.gz: ad45bd8133d5f68bcf190bac3f7656864e10df2e49be477024e9f0c8422ce222
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f2e5c4ac4020dfd7aaed53bfb9b7e7480ca91e0aa7cfcbc385ac60d91a4b08e40397734993ffdffc9d5121f40afab04540d363fef925bf8a30bf987938514ab
|
7
|
+
data.tar.gz: 3460da22048d4fad135e12644c043723b2dcba8137a69a3b5bebf3b5df11e1c1a0ed0f94a8924b64cab4d1ce8b76bd55e6090a25c43f23afde41b27d398cf59a
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,37 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v4.5.0](https://github.com/bensheldon/good_job/tree/v4.5.0) (2024-11-22)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v4.4.2...v4.5.0)
|
6
|
+
|
7
|
+
**Implemented enhancements:**
|
8
|
+
|
9
|
+
- Add "Discard Cleaner" page to dashboard UI [\#1538](https://github.com/bensheldon/good_job/pull/1538) ([lucasfcunha](https://github.com/lucasfcunha))
|
10
|
+
- Add Process memory usage and fix process state update [\#1516](https://github.com/bensheldon/good_job/pull/1516) ([noma4i](https://github.com/noma4i))
|
11
|
+
|
12
|
+
**Fixed bugs:**
|
13
|
+
|
14
|
+
- Fix cron double-enqueue because delay close to 0.01 and possibly clock-drift [\#1543](https://github.com/bensheldon/good_job/pull/1543) ([ccouton](https://github.com/ccouton))
|
15
|
+
- Fix badge color for running jobs [\#1525](https://github.com/bensheldon/good_job/pull/1525) ([Wittiest](https://github.com/Wittiest))
|
16
|
+
|
17
|
+
**Closed issues:**
|
18
|
+
|
19
|
+
- Can't load Dashboard [\#1532](https://github.com/bensheldon/good_job/issues/1532)
|
20
|
+
- Should we clean up batches if discarded callback jobs exist? [\#1528](https://github.com/bensheldon/good_job/issues/1528)
|
21
|
+
- Modify error color for Running tab when a job has 1 attempt [\#1518](https://github.com/bensheldon/good_job/issues/1518)
|
22
|
+
- Silence development warning output [\#1509](https://github.com/bensheldon/good_job/issues/1509)
|
23
|
+
- Proposal - A better way of managing errors through the GoodJob UI [\#1464](https://github.com/bensheldon/good_job/issues/1464)
|
24
|
+
|
25
|
+
**Merged pull requests:**
|
26
|
+
|
27
|
+
- Ignore some warnings with the `warning` gem [\#1545](https://github.com/bensheldon/good_job/pull/1545) ([Earlopain](https://github.com/Earlopain))
|
28
|
+
- Remove unneeded include of pg\_locks in query when displaying jobs table [\#1541](https://github.com/bensheldon/good_job/pull/1541) ([jgrau](https://github.com/jgrau))
|
29
|
+
- Update development environment to Rails 8 [\#1539](https://github.com/bensheldon/good_job/pull/1539) ([bensheldon](https://github.com/bensheldon))
|
30
|
+
- Bump the bundler-dependencies group with 9 updates [\#1534](https://github.com/bensheldon/good_job/pull/1534) ([dependabot[bot]](https://github.com/apps/dependabot))
|
31
|
+
- Bump the bundler-lint group with 5 updates [\#1533](https://github.com/bensheldon/good_job/pull/1533) ([dependabot[bot]](https://github.com/apps/dependabot))
|
32
|
+
- Bump rexml from 3.3.8 to 3.3.9 [\#1530](https://github.com/bensheldon/good_job/pull/1530) ([dependabot[bot]](https://github.com/apps/dependabot))
|
33
|
+
- Deprecate GoodJob::Job\#recent\_error [\#1526](https://github.com/bensheldon/good_job/pull/1526) ([Wittiest](https://github.com/Wittiest))
|
34
|
+
|
3
35
|
## [v4.4.2](https://github.com/bensheldon/good_job/tree/v4.4.2) (2024-10-18)
|
4
36
|
|
5
37
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v4.4.1...v4.4.2)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GoodJob
|
4
|
+
class CleanerController < ApplicationController
|
5
|
+
def index
|
6
|
+
@filter = JobsFilter.new(params)
|
7
|
+
|
8
|
+
@discarded_jobs_grouped_by_exception =
|
9
|
+
GoodJob::Job.discarded
|
10
|
+
.select(<<-SQL.squish)
|
11
|
+
SPLIT_PART(error, ': ', 1) AS exception_class,
|
12
|
+
count(id) AS failed,
|
13
|
+
COUNT(id) FILTER (WHERE "finished_at" > NOW() - INTERVAL '1 HOUR') AS last_1_hour,
|
14
|
+
COUNT(id) FILTER (WHERE "finished_at" > NOW() - INTERVAL '3 HOURS') AS last_3_hours,
|
15
|
+
COUNT(id) FILTER (WHERE "finished_at" > NOW() - INTERVAL '24 HOURS') AS last_24_hours,
|
16
|
+
COUNT(id) FILTER (WHERE "finished_at" > NOW() - INTERVAL '3 DAYS') AS last_3_days,
|
17
|
+
COUNT(id) FILTER (WHERE "finished_at" > NOW() - INTERVAL '7 DAYS') AS last_7_days
|
18
|
+
SQL
|
19
|
+
.order(:exception_class)
|
20
|
+
.group(:exception_class)
|
21
|
+
|
22
|
+
@discarded_jobs_grouped_by_class =
|
23
|
+
GoodJob::Job.discarded
|
24
|
+
.select(<<-SQL.squish)
|
25
|
+
job_class,
|
26
|
+
count(id) AS failed,
|
27
|
+
COUNT(*) FILTER (WHERE "finished_at" > NOW() - INTERVAL '1 HOUR') AS last_1_hour,
|
28
|
+
COUNT(*) FILTER (WHERE "finished_at" > NOW() - INTERVAL '3 HOURS') AS last_3_hours,
|
29
|
+
COUNT(*) FILTER (WHERE "finished_at" > NOW() - INTERVAL '24 HOURS') AS last_24_hours,
|
30
|
+
COUNT(*) FILTER (WHERE "finished_at" > NOW() - INTERVAL '3 DAYS') AS last_3_days,
|
31
|
+
COUNT(*) FILTER (WHERE "finished_at" > NOW() - INTERVAL '7 DAYS') AS last_7_days
|
32
|
+
SQL
|
33
|
+
.order(:job_class)
|
34
|
+
.group(:job_class)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -7,12 +7,14 @@ module GoodJob
|
|
7
7
|
batches_count = GoodJob::BatchRecord.all.size
|
8
8
|
cron_entries_count = GoodJob::CronEntry.all.size
|
9
9
|
processes_count = GoodJob::Process.active.count
|
10
|
+
discarded_count = GoodJob::Job.discarded.count
|
10
11
|
|
11
12
|
render json: {
|
12
13
|
jobs_count: helpers.number_to_human(jobs_count),
|
13
14
|
batches_count: helpers.number_to_human(batches_count),
|
14
15
|
cron_entries_count: helpers.number_to_human(cron_entries_count),
|
15
16
|
processes_count: helpers.number_to_human(processes_count),
|
17
|
+
discarded_count: helpers.number_to_human(discarded_count),
|
16
18
|
}
|
17
19
|
end
|
18
20
|
|
@@ -27,6 +27,7 @@ module GoodJob
|
|
27
27
|
query = query.where(queue_name: filter_params[:queue_name]) if filter_params[:queue_name].present?
|
28
28
|
query = query.search_text(filter_params[:query]) if filter_params[:query].present?
|
29
29
|
query = query.where(cron_key: filter_params[:cron_key]) if filter_params[:cron_key].present?
|
30
|
+
query = query.where(finished_at: finished_since(filter_params[:finished_since])..) if filter_params[:finished_since].present?
|
30
31
|
|
31
32
|
if filter_params[:state]
|
32
33
|
case filter_params[:state]
|
@@ -39,7 +40,7 @@ module GoodJob
|
|
39
40
|
when 'scheduled'
|
40
41
|
query = query.scheduled
|
41
42
|
when 'running'
|
42
|
-
query = query.running
|
43
|
+
query = query.running
|
43
44
|
when 'queued'
|
44
45
|
query = query.queued
|
45
46
|
end
|
@@ -55,11 +56,26 @@ module GoodJob
|
|
55
56
|
private
|
56
57
|
|
57
58
|
def query_for_records
|
58
|
-
filtered_query
|
59
|
+
filtered_query
|
59
60
|
end
|
60
61
|
|
61
62
|
def default_base_query
|
62
63
|
GoodJob::Job.all
|
63
64
|
end
|
65
|
+
|
66
|
+
def finished_since(finished_since)
|
67
|
+
case finished_since
|
68
|
+
when '1_hour_ago'
|
69
|
+
1.hour.ago
|
70
|
+
when '3_hours_ago'
|
71
|
+
3.hours.ago
|
72
|
+
when '24_hours_ago'
|
73
|
+
24.hours.ago
|
74
|
+
when '3_days_ago'
|
75
|
+
3.days.ago
|
76
|
+
when '7_days_ago'
|
77
|
+
7.days.ago
|
78
|
+
end
|
79
|
+
end
|
64
80
|
end
|
65
81
|
end
|
data/app/models/good_job/job.rb
CHANGED
@@ -390,7 +390,12 @@ module GoodJob
|
|
390
390
|
# If the job has been retried, the error will be fetched from the previous {Execution} record.
|
391
391
|
# @return [String]
|
392
392
|
def recent_error
|
393
|
-
|
393
|
+
GoodJob.deprecator.warn(<<~DEPRECATION)
|
394
|
+
The `GoodJob::Job#recent_error` method is deprecated and will be removed in the next major release.
|
395
|
+
|
396
|
+
Replace usage of GoodJob::Job#recent_error with `GoodJob::Job#error`.
|
397
|
+
DEPRECATION
|
398
|
+
error
|
394
399
|
end
|
395
400
|
|
396
401
|
# Errors for the job to be displayed in the Dashboard.
|
@@ -12,6 +12,28 @@ module GoodJob # :nodoc:
|
|
12
12
|
STALE_INTERVAL = 30.seconds
|
13
13
|
# Interval until the process record is treated as expired
|
14
14
|
EXPIRED_INTERVAL = 5.minutes
|
15
|
+
PROCESS_MEMORY = case RUBY_PLATFORM
|
16
|
+
when /linux/
|
17
|
+
lambda do |pid|
|
18
|
+
File.readlines("/proc/#{pid}/smaps_rollup").each do |line|
|
19
|
+
next unless line.start_with?('Pss:')
|
20
|
+
|
21
|
+
break line.split[1].to_i
|
22
|
+
end
|
23
|
+
rescue Errno::ENOENT
|
24
|
+
File.readlines("/proc/#{pid}/status").each do |line|
|
25
|
+
next unless line.start_with?('VmRSS:')
|
26
|
+
|
27
|
+
break line.split[1].to_i
|
28
|
+
end
|
29
|
+
end
|
30
|
+
when /darwin|bsd/
|
31
|
+
lambda do |pid|
|
32
|
+
`ps -o pid,rss -p #{pid.to_i}`.lines.last.split.last.to_i
|
33
|
+
end
|
34
|
+
else
|
35
|
+
->(_pid) { 0 }
|
36
|
+
end
|
15
37
|
|
16
38
|
self.table_name = 'good_job_processes'
|
17
39
|
self.implicit_order_column = 'created_at'
|
@@ -56,6 +78,13 @@ module GoodJob # :nodoc:
|
|
56
78
|
end
|
57
79
|
end
|
58
80
|
|
81
|
+
# @return [Integer]
|
82
|
+
def self.memory_usage(pid)
|
83
|
+
PROCESS_MEMORY.call(pid)
|
84
|
+
rescue StandardError
|
85
|
+
0
|
86
|
+
end
|
87
|
+
|
59
88
|
def self.find_or_create_record(id:, with_advisory_lock: false)
|
60
89
|
attributes = {
|
61
90
|
id: id,
|
@@ -83,6 +112,7 @@ module GoodJob # :nodoc:
|
|
83
112
|
{
|
84
113
|
hostname: Socket.gethostname,
|
85
114
|
pid: ::Process.pid,
|
115
|
+
memory: memory_usage(::Process.pid),
|
86
116
|
proctitle: $PROGRAM_NAME,
|
87
117
|
preserve_job_records: GoodJob.preserve_job_records,
|
88
118
|
retry_on_unhandled_error: GoodJob.retry_on_unhandled_error,
|
@@ -98,8 +128,8 @@ module GoodJob # :nodoc:
|
|
98
128
|
end
|
99
129
|
|
100
130
|
def refresh
|
101
|
-
self.state = self.class.process_state
|
102
131
|
reload # verify the record still exists in the database
|
132
|
+
self.state = self.class.process_state
|
103
133
|
update(state: state, updated_at: Time.current)
|
104
134
|
rescue ActiveRecord::RecordNotFound
|
105
135
|
@new_record = true
|
@@ -35,17 +35,18 @@
|
|
35
35
|
</div>
|
36
36
|
<div class="col-4 col-lg-1 text-lg-end">
|
37
37
|
<div class="d-lg-none small text-muted mt-1"><%= t "good_job.models.job.attempts" %></div>
|
38
|
-
<% if job.
|
38
|
+
<% if job.error %>
|
39
39
|
<%= tag.span job.executions_count, class: "badge rounded-pill bg-danger",
|
40
40
|
data: {
|
41
41
|
bs_toggle: "popover",
|
42
42
|
bs_trigger: "hover focus click",
|
43
43
|
bs_placement: "bottom",
|
44
|
-
bs_content: job.
|
44
|
+
bs_content: job.display_error,
|
45
45
|
}
|
46
46
|
%>
|
47
47
|
<% else %>
|
48
|
-
|
48
|
+
<% executions_badge_color = job.executions_count > 1 ? "bg-warning" : "bg-secondary" %>
|
49
|
+
<span class="badge rounded-pill <%= executions_badge_color %>"><%= job.executions_count %></span>
|
49
50
|
<% end %>
|
50
51
|
</div>
|
51
52
|
<div class="mt-3 mt-lg-0 col d-flex gap-3 align-items-center justify-content-end">
|
@@ -79,7 +80,7 @@
|
|
79
80
|
<% end %>
|
80
81
|
</li>
|
81
82
|
<li>
|
82
|
-
<%= link_to job_path(job.id), method: :delete, class: "dropdown-item #{'disabled' unless job.
|
83
|
+
<%= link_to job_path(job.id), method: :delete, class: "dropdown-item #{'disabled' unless job.finished?}", title: t(".actions.destroy"), data: { confirm: t(".actions.confirm_destroy"), disable: true } do %>
|
83
84
|
<%= render_icon "trash" %>
|
84
85
|
<%= t "good_job.actions.destroy" %>
|
85
86
|
<% end %>
|
@@ -0,0 +1,85 @@
|
|
1
|
+
<div class="border-bottom">
|
2
|
+
<h2 class="pt-3 pb-2"><%= t ".title" %></h2>
|
3
|
+
</div>
|
4
|
+
|
5
|
+
<div>
|
6
|
+
<h4 class="pt-3 pb-2"><%= t ".grouped_by_class" %></h4>
|
7
|
+
<table class="table align-middle" id="by-job-class">
|
8
|
+
<thead>
|
9
|
+
<tr>
|
10
|
+
<th scope="col" class="col-3"><%= t ".class" %></th>
|
11
|
+
<th scope="col" class="text-center"><%= t ".all" %></th>
|
12
|
+
<th scope="col" class="text-center"><%= t ".last_1_hour" %></th>
|
13
|
+
<th scope="col" class="text-center"><%= t ".last_3_hours" %></th>
|
14
|
+
<th scope="col" class="text-center"><%= t ".last_24_hours" %></th>
|
15
|
+
<th scope="col" class="text-center"><%= t ".last_3_days" %></th>
|
16
|
+
<th scope="col" class="text-center"><%= t ".last_7_days" %></th>
|
17
|
+
</tr>
|
18
|
+
</thead>
|
19
|
+
<tbody>
|
20
|
+
<% @discarded_jobs_grouped_by_class.each do |discard_job| %>
|
21
|
+
<tr>
|
22
|
+
<td scope="row" class="col-3 text-break"><%= discard_job.job_class %></td>
|
23
|
+
<td class="text-center "><%= link_to discard_job.failed, jobs_path(@filter.to_params(job_class: discard_job.job_class, state: 'discarded')) %></td>
|
24
|
+
<td class="text-center"><%= link_to discard_job.last_1_hour, jobs_path(@filter.to_params(job_class: discard_job.job_class, state: 'discarded', finished_since: '1_hour_ago')) %></td>
|
25
|
+
<td class="text-center"><%= link_to discard_job.last_3_hours, jobs_path(@filter.to_params(job_class: discard_job.job_class, state: 'discarded', finished_since: '3_hours_ago')) %></td>
|
26
|
+
<td class="text-center"><%= link_to discard_job.last_24_hours, jobs_path(@filter.to_params(job_class: discard_job.job_class, state: 'discarded', finished_since: '24_hours_ago')) %></td>
|
27
|
+
<td class="text-center"><%= link_to discard_job.last_3_days, jobs_path(@filter.to_params(job_class: discard_job.job_class, state: 'discarded', finished_since: '3_days_ago')) %></td>
|
28
|
+
<td class="text-center"><%= link_to discard_job.last_7_days, jobs_path(@filter.to_params(job_class: discard_job.job_class, state: 'discarded', finished_since: '7_days_ago')) %></td>
|
29
|
+
</tr>
|
30
|
+
<% end %>
|
31
|
+
</tbody>
|
32
|
+
<tfoot>
|
33
|
+
<tr>
|
34
|
+
<td scope="row" class="col-3 fw-bold"><%= t ".total" %></td>
|
35
|
+
<td class="text-center fw-bold"><%= link_to @discarded_jobs_grouped_by_class.sum(&:failed), jobs_path(@filter.to_params(state: 'discarded')) %></td>
|
36
|
+
<td class="text-center fw-bold"><%= link_to @discarded_jobs_grouped_by_class.sum(&:last_1_hour), jobs_path(@filter.to_params(state: 'discarded', finished_since: '1_hour_ago')) %></td>
|
37
|
+
<td class="text-center fw-bold"><%= link_to @discarded_jobs_grouped_by_class.sum(&:last_3_hours), jobs_path(@filter.to_params(state: 'discarded', finished_since: '3_hours_ago')) %></td>
|
38
|
+
<td class="text-center fw-bold"><%= link_to @discarded_jobs_grouped_by_class.sum(&:last_24_hours), jobs_path(@filter.to_params(state: 'discarded', finished_since: '24_hours_ago')) %></td>
|
39
|
+
<td class="text-center fw-bold"><%= link_to @discarded_jobs_grouped_by_class.sum(&:last_3_days), jobs_path(@filter.to_params(state: 'discarded', finished_since: '3_days_ago')) %></td>
|
40
|
+
<td class="text-center fw-bold"><%= link_to @discarded_jobs_grouped_by_class.sum(&:last_7_days), jobs_path(@filter.to_params(state: 'discarded', finished_since: '7_days_ago')) %></td>
|
41
|
+
</tr>
|
42
|
+
</tfoot>
|
43
|
+
</table>
|
44
|
+
</div>
|
45
|
+
|
46
|
+
<div>
|
47
|
+
<h4 class="pt-3 pb-2"><%= t ".grouped_by_exception" %></h4>
|
48
|
+
<table class="table align-middle" id="by-exception">
|
49
|
+
<thead>
|
50
|
+
<tr>
|
51
|
+
<th scope="col" class="col-3"><%= t ".exception" %></th>
|
52
|
+
<th scope="col" class="text-center"><%= t ".all" %></th>
|
53
|
+
<th scope="col" class="text-center"><%= t ".last_1_hour" %></th>
|
54
|
+
<th scope="col" class="text-center"><%= t ".last_3_hours" %></th>
|
55
|
+
<th scope="col" class="text-center"><%= t ".last_24_hours" %></th>
|
56
|
+
<th scope="col" class="text-center"><%= t ".last_3_days" %></th>
|
57
|
+
<th scope="col" class="text-center"><%= t ".last_7_days" %></th>
|
58
|
+
</tr>
|
59
|
+
</thead>
|
60
|
+
<tbody>
|
61
|
+
<% @discarded_jobs_grouped_by_exception.each do |discard_job| %>
|
62
|
+
<tr>
|
63
|
+
<td scope="row" class="col-3 text-break"><%= discard_job.exception_class %></td>
|
64
|
+
<td class="text-center"><%= link_to discard_job.failed, jobs_path(@filter.to_params(state: 'discarded', query: discard_job.exception_class)) %></td>
|
65
|
+
<td class="text-center"><%= link_to discard_job.last_1_hour, jobs_path(@filter.to_params(state: 'discarded', query: discard_job.exception_class, finished_since: '1_hour_ago')) %></td>
|
66
|
+
<td class="text-center"><%= link_to discard_job.last_3_hours, jobs_path(@filter.to_params(state: 'discarded', query: discard_job.exception_class, finished_since: '3_hours_ago')) %></td>
|
67
|
+
<td class="text-center"><%= link_to discard_job.last_24_hours, jobs_path(@filter.to_params(state: 'discarded', query: discard_job.exception_class, finished_since: '24_hours_ago')) %></td>
|
68
|
+
<td class="text-center"><%= link_to discard_job.last_3_days, jobs_path(@filter.to_params(state: 'discarded', query: discard_job.exception_class, finished_since: '3_days_ago')) %></td>
|
69
|
+
<td class="text-center"><%= link_to discard_job.last_7_days, jobs_path(@filter.to_params(state: 'discarded', query: discard_job.exception_class, finished_since: '7_days_ago')) %></td>
|
70
|
+
</tr>
|
71
|
+
<% end %>
|
72
|
+
</tbody>
|
73
|
+
<tfoot>
|
74
|
+
<tr>
|
75
|
+
<td scope="row" class="col-3 fw-bold"><%= t ".total" %></td>
|
76
|
+
<td class="text-center fw-bold"><%= link_to @discarded_jobs_grouped_by_exception.sum(&:failed), jobs_path(@filter.to_params(state: 'discarded')) %></td>
|
77
|
+
<td class="text-center fw-bold"><%= link_to @discarded_jobs_grouped_by_exception.sum(&:last_1_hour), jobs_path(@filter.to_params(state: 'discarded', finished_since: '1_hour_ago')) %></td>
|
78
|
+
<td class="text-center fw-bold"><%= link_to @discarded_jobs_grouped_by_exception.sum(&:last_3_hours), jobs_path(@filter.to_params(state: 'discarded', finished_since: '3_hours_ago')) %></td>
|
79
|
+
<td class="text-center fw-bold"><%= link_to @discarded_jobs_grouped_by_exception.sum(&:last_24_hours), jobs_path(@filter.to_params(state: 'discarded', finished_since: '24_hours_ago')) %></td>
|
80
|
+
<td class="text-center fw-bold"><%= link_to @discarded_jobs_grouped_by_exception.sum(&:last_3_days), jobs_path(@filter.to_params(state: 'discarded', finished_since: '3_days_ago')) %></td>
|
81
|
+
<td class="text-center fw-bold"><%= link_to @discarded_jobs_grouped_by_exception.sum(&:last_7_days), jobs_path(@filter.to_params(state: 'discarded', finished_since: '7_days_ago')) %></td>
|
82
|
+
</tr>
|
83
|
+
</tfoot>
|
84
|
+
</table>
|
85
|
+
</div>
|
@@ -84,7 +84,7 @@
|
|
84
84
|
</div>
|
85
85
|
<div class="col-4 col-lg-1 text-lg-end">
|
86
86
|
<div class="d-lg-none small text-muted mt-1"><%= t "good_job.models.job.attempts" %></div>
|
87
|
-
<% if job.
|
87
|
+
<% if job.error %>
|
88
88
|
<%= tag.span job.executions_count, class: "badge rounded-pill bg-danger",
|
89
89
|
data: {
|
90
90
|
bs_toggle: "popover",
|
@@ -94,7 +94,8 @@
|
|
94
94
|
}
|
95
95
|
%>
|
96
96
|
<% else %>
|
97
|
-
|
97
|
+
<% executions_badge_color = job.executions_count > 1 ? "bg-warning" : "bg-secondary" %>
|
98
|
+
<span class="badge rounded-pill <%= executions_badge_color %>"><%= job.executions_count %></span>
|
98
99
|
<% end %>
|
99
100
|
</div>
|
100
101
|
<div class="mt-3 mt-lg-0 col">
|
@@ -38,6 +38,7 @@
|
|
38
38
|
<span class="badge rounded-pill bg-body-secondary text-secondary"><%= process.state["pid"] %></span>
|
39
39
|
<span class="text-muted small">@</span>
|
40
40
|
<span class="badge rounded-pill bg-body-secondary text-secondary"><%= process.state["hostname"] %></span>
|
41
|
+
<span class="badge rounded-pill bg-body-secondary text-secondary"><%= (process.state["memory"] / 1024).to_i %> MB</span>
|
41
42
|
</div>
|
42
43
|
</div>
|
43
44
|
<div class="col">
|
@@ -44,6 +44,12 @@
|
|
44
44
|
<%= t(".performance") %>
|
45
45
|
<% end %>
|
46
46
|
</li>
|
47
|
+
<li class="nav-item">
|
48
|
+
<%= link_to cleaner_index_path, class: ["nav-link", ("active" if controller_name == 'cleaner')] do %>
|
49
|
+
<%= t(".cleaner") %>
|
50
|
+
<span data-async-values-target="value" data-async-values-key="discarded_count" class="badge bg-secondary rounded-pill d-none"></span>
|
51
|
+
<% end %>
|
52
|
+
</li>
|
47
53
|
</ul>
|
48
54
|
|
49
55
|
<ul class="navbar-nav">
|
data/config/brakeman.ignore
CHANGED
@@ -53,7 +53,7 @@
|
|
53
53
|
"check_name": "SQL",
|
54
54
|
"message": "Possible SQL injection",
|
55
55
|
"file": "app/models/good_job/job.rb",
|
56
|
-
"line":
|
56
|
+
"line": 135,
|
57
57
|
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
58
58
|
"code": "Arel.sql(\"(CASE #{queues.map.with_index do\n sanitize_sql_array([\"WHEN queue_name = ? THEN ?\", queue_name, index])\n end.join(\" \")} ELSE #{queues.size} END)\")",
|
59
59
|
"render_path": null,
|
@@ -68,8 +68,31 @@
|
|
68
68
|
89
|
69
69
|
],
|
70
70
|
"note": "Developer provided value, queue_name, is sanitized."
|
71
|
+
},
|
72
|
+
{
|
73
|
+
"warning_type": "Command Injection",
|
74
|
+
"warning_code": 14,
|
75
|
+
"fingerprint": "dbb80167f57edebfd9da72e1278d425095a0329755e24d3c50e0fda6bb21c097",
|
76
|
+
"check_name": "Execute",
|
77
|
+
"message": "Possible command injection",
|
78
|
+
"file": "app/models/good_job/process.rb",
|
79
|
+
"line": 32,
|
80
|
+
"link": "https://brakemanscanner.org/docs/warning_types/command_injection/",
|
81
|
+
"code": "`ps -o pid,rss -p #{pid.to_i}`",
|
82
|
+
"render_path": null,
|
83
|
+
"location": {
|
84
|
+
"type": "method",
|
85
|
+
"class": "Process",
|
86
|
+
"method": null
|
87
|
+
},
|
88
|
+
"user_input": "pid.to_i",
|
89
|
+
"confidence": "Medium",
|
90
|
+
"cwe_id": [
|
91
|
+
77
|
92
|
+
],
|
93
|
+
"note": ""
|
71
94
|
}
|
72
95
|
],
|
73
|
-
"updated": "2024-
|
74
|
-
"brakeman_version": "6.1
|
96
|
+
"updated": "2024-11-16 17:00:20 -0600",
|
97
|
+
"brakeman_version": "6.2.1"
|
75
98
|
}
|
data/config/locales/de.yml
CHANGED
@@ -35,6 +35,20 @@ de:
|
|
35
35
|
callback_jobs: Callback-Jobs
|
36
36
|
table:
|
37
37
|
no_batches_found: Keine Batches gefunden.
|
38
|
+
cleaner:
|
39
|
+
index:
|
40
|
+
all: All
|
41
|
+
class: Class
|
42
|
+
exception: Exception
|
43
|
+
grouped_by_class: Discards grouped by Class
|
44
|
+
grouped_by_exception: Discards grouped by Exception
|
45
|
+
last_1_hour: Last 1 hour
|
46
|
+
last_24_hours: Last 24 hours
|
47
|
+
last_3_days: Last 3 days
|
48
|
+
last_3_hours: Last 3 hours
|
49
|
+
last_7_days: Last 7 days
|
50
|
+
title: Discard Cleaner
|
51
|
+
total: Total
|
38
52
|
cron_entries:
|
39
53
|
actions:
|
40
54
|
confirm_disable: Bist du sicher, dass du diesen Cron-Eintrag deaktivieren willst?
|
@@ -236,6 +250,7 @@ de:
|
|
236
250
|
search: Suchen
|
237
251
|
navbar:
|
238
252
|
batches: Batches
|
253
|
+
cleaner: Discard Cleaner
|
239
254
|
cron_schedules: Cron
|
240
255
|
jobs: Jobs
|
241
256
|
live_poll: Live Poll
|
data/config/locales/en.yml
CHANGED
@@ -35,6 +35,20 @@ en:
|
|
35
35
|
callback_jobs: Callback Jobs
|
36
36
|
table:
|
37
37
|
no_batches_found: No batches found.
|
38
|
+
cleaner:
|
39
|
+
index:
|
40
|
+
all: All
|
41
|
+
class: Class
|
42
|
+
exception: Exception
|
43
|
+
grouped_by_class: Discards grouped by Class
|
44
|
+
grouped_by_exception: Discards grouped by Exception
|
45
|
+
last_1_hour: Last 1 hour
|
46
|
+
last_24_hours: Last 24 hours
|
47
|
+
last_3_days: Last 3 days
|
48
|
+
last_3_hours: Last 3 hours
|
49
|
+
last_7_days: Last 7 days
|
50
|
+
title: Discard Cleaner
|
51
|
+
total: Total
|
38
52
|
cron_entries:
|
39
53
|
actions:
|
40
54
|
confirm_disable: Are you sure you want to disable this cron entry?
|
@@ -236,6 +250,7 @@ en:
|
|
236
250
|
search: Search
|
237
251
|
navbar:
|
238
252
|
batches: Batches
|
253
|
+
cleaner: Discard Cleaner
|
239
254
|
cron_schedules: Cron
|
240
255
|
jobs: Jobs
|
241
256
|
live_poll: Live Poll
|
data/config/locales/es.yml
CHANGED
@@ -35,6 +35,20 @@ es:
|
|
35
35
|
callback_jobs: Callback Jobs
|
36
36
|
table:
|
37
37
|
no_batches_found: No hay lotes.
|
38
|
+
cleaner:
|
39
|
+
index:
|
40
|
+
all: All
|
41
|
+
class: Class
|
42
|
+
exception: Exception
|
43
|
+
grouped_by_class: Discards grouped by Class
|
44
|
+
grouped_by_exception: Discards grouped by Exception
|
45
|
+
last_1_hour: Last 1 hour
|
46
|
+
last_24_hours: Last 24 hours
|
47
|
+
last_3_days: Last 3 days
|
48
|
+
last_3_hours: Last 3 hours
|
49
|
+
last_7_days: Last 7 days
|
50
|
+
title: Discard Cleaner
|
51
|
+
total: Total
|
38
52
|
cron_entries:
|
39
53
|
actions:
|
40
54
|
confirm_disable: "¿Estás seguro que querés deshabilitar esta tarea programada?"
|
@@ -236,6 +250,7 @@ es:
|
|
236
250
|
search: Buscar
|
237
251
|
navbar:
|
238
252
|
batches: Lotes
|
253
|
+
cleaner: Discard Cleaner
|
239
254
|
cron_schedules: Cron
|
240
255
|
jobs: Tareas
|
241
256
|
live_poll: En vivo
|
data/config/locales/fr.yml
CHANGED
@@ -35,6 +35,20 @@ fr:
|
|
35
35
|
callback_jobs: Jobs de rappel
|
36
36
|
table:
|
37
37
|
no_batches_found: Aucun lot trouvé.
|
38
|
+
cleaner:
|
39
|
+
index:
|
40
|
+
all: All
|
41
|
+
class: Class
|
42
|
+
exception: Exception
|
43
|
+
grouped_by_class: Discards grouped by Class
|
44
|
+
grouped_by_exception: Discards grouped by Exception
|
45
|
+
last_1_hour: Last 1 hour
|
46
|
+
last_24_hours: Last 24 hours
|
47
|
+
last_3_days: Last 3 days
|
48
|
+
last_3_hours: Last 3 hours
|
49
|
+
last_7_days: Last 7 days
|
50
|
+
title: Discard Cleaner
|
51
|
+
total: Total
|
38
52
|
cron_entries:
|
39
53
|
actions:
|
40
54
|
confirm_disable: Voulez-vous vraiment désactiver cette entrée cron ?
|
@@ -236,6 +250,7 @@ fr:
|
|
236
250
|
search: Rechercher
|
237
251
|
navbar:
|
238
252
|
batches: Lots
|
253
|
+
cleaner: Discard Cleaner
|
239
254
|
cron_schedules: Cron
|
240
255
|
jobs: Jobs
|
241
256
|
live_poll: En direct
|
data/config/locales/it.yml
CHANGED
@@ -35,6 +35,20 @@ it:
|
|
35
35
|
callback_jobs: Job di callback
|
36
36
|
table:
|
37
37
|
no_batches_found: Nessun batch trovato.
|
38
|
+
cleaner:
|
39
|
+
index:
|
40
|
+
all: All
|
41
|
+
class: Class
|
42
|
+
exception: Exception
|
43
|
+
grouped_by_class: Discards grouped by Class
|
44
|
+
grouped_by_exception: Discards grouped by Exception
|
45
|
+
last_1_hour: Last 1 hour
|
46
|
+
last_24_hours: Last 24 hours
|
47
|
+
last_3_days: Last 3 days
|
48
|
+
last_3_hours: Last 3 hours
|
49
|
+
last_7_days: Last 7 days
|
50
|
+
title: Discard Cleaner
|
51
|
+
total: Total
|
38
52
|
cron_entries:
|
39
53
|
actions:
|
40
54
|
confirm_disable: Sei sicuro di voler disabilitare questa voce cron?
|
@@ -236,6 +250,7 @@ it:
|
|
236
250
|
search: Cerca
|
237
251
|
navbar:
|
238
252
|
batches: Batch
|
253
|
+
cleaner: Discard Cleaner
|
239
254
|
cron_schedules: Cron
|
240
255
|
jobs: Job
|
241
256
|
live_poll: Live Poll
|
data/config/locales/ja.yml
CHANGED
@@ -35,6 +35,20 @@ ja:
|
|
35
35
|
callback_jobs: コールバックジョブ
|
36
36
|
table:
|
37
37
|
no_batches_found: バッチが見つかりませんでした。
|
38
|
+
cleaner:
|
39
|
+
index:
|
40
|
+
all: All
|
41
|
+
class: Class
|
42
|
+
exception: Exception
|
43
|
+
grouped_by_class: Discards grouped by Class
|
44
|
+
grouped_by_exception: Discards grouped by Exception
|
45
|
+
last_1_hour: Last 1 hour
|
46
|
+
last_24_hours: Last 24 hours
|
47
|
+
last_3_days: Last 3 days
|
48
|
+
last_3_hours: Last 3 hours
|
49
|
+
last_7_days: Last 7 days
|
50
|
+
title: Discard Cleaner
|
51
|
+
total: Total
|
38
52
|
cron_entries:
|
39
53
|
actions:
|
40
54
|
confirm_disable: このcronエントリを無効化してもよろしいですか?
|
@@ -236,6 +250,7 @@ ja:
|
|
236
250
|
search: 検索
|
237
251
|
navbar:
|
238
252
|
batches: バッチ
|
253
|
+
cleaner: Discard Cleaner
|
239
254
|
cron_schedules: Cron
|
240
255
|
jobs: ジョブ
|
241
256
|
live_poll: リアルタイム更新
|
data/config/locales/ko.yml
CHANGED
@@ -35,6 +35,20 @@ ko:
|
|
35
35
|
callback_jobs: 콜백 작업
|
36
36
|
table:
|
37
37
|
no_batches_found: 배치를 찾을 수 없습니다.
|
38
|
+
cleaner:
|
39
|
+
index:
|
40
|
+
all: All
|
41
|
+
class: Class
|
42
|
+
exception: Exception
|
43
|
+
grouped_by_class: Discards grouped by Class
|
44
|
+
grouped_by_exception: Discards grouped by Exception
|
45
|
+
last_1_hour: Last 1 hour
|
46
|
+
last_24_hours: Last 24 hours
|
47
|
+
last_3_days: Last 3 days
|
48
|
+
last_3_hours: Last 3 hours
|
49
|
+
last_7_days: Last 7 days
|
50
|
+
title: Discard Cleaner
|
51
|
+
total: Total
|
38
52
|
cron_entries:
|
39
53
|
actions:
|
40
54
|
confirm_disable: 이 cron 엔트리를 비활성화하시겠습니까?
|
@@ -236,6 +250,7 @@ ko:
|
|
236
250
|
search: 검색
|
237
251
|
navbar:
|
238
252
|
batches: 배치
|
253
|
+
cleaner: Discard Cleaner
|
239
254
|
cron_schedules: Cron
|
240
255
|
jobs: 작업
|
241
256
|
live_poll: 실시간 업데이트
|
data/config/locales/nl.yml
CHANGED
@@ -35,6 +35,20 @@ nl:
|
|
35
35
|
callback_jobs: Terugbelopdrachten
|
36
36
|
table:
|
37
37
|
no_batches_found: Geen batches gevonden.
|
38
|
+
cleaner:
|
39
|
+
index:
|
40
|
+
all: All
|
41
|
+
class: Class
|
42
|
+
exception: Exception
|
43
|
+
grouped_by_class: Discards grouped by Class
|
44
|
+
grouped_by_exception: Discards grouped by Exception
|
45
|
+
last_1_hour: Last 1 hour
|
46
|
+
last_24_hours: Last 24 hours
|
47
|
+
last_3_days: Last 3 days
|
48
|
+
last_3_hours: Last 3 hours
|
49
|
+
last_7_days: Last 7 days
|
50
|
+
title: Discard Cleaner
|
51
|
+
total: Total
|
38
52
|
cron_entries:
|
39
53
|
actions:
|
40
54
|
confirm_disable: Weet u zekerf dat u deze cron-vermelding wilt uitschakelen?
|
@@ -236,6 +250,7 @@ nl:
|
|
236
250
|
search: Zoekopdracht
|
237
251
|
navbar:
|
238
252
|
batches: Batches
|
253
|
+
cleaner: Discard Cleaner
|
239
254
|
cron_schedules: Cron
|
240
255
|
jobs: Taken
|
241
256
|
live_poll: Live Poll
|
data/config/locales/pt-BR.yml
CHANGED
@@ -35,6 +35,20 @@ pt-BR:
|
|
35
35
|
callback_jobs: Tarefas de Callback
|
36
36
|
table:
|
37
37
|
no_batches_found: Nenhum lote encontrado.
|
38
|
+
cleaner:
|
39
|
+
index:
|
40
|
+
all: All
|
41
|
+
class: Class
|
42
|
+
exception: Exception
|
43
|
+
grouped_by_class: Discards grouped by Class
|
44
|
+
grouped_by_exception: Discards grouped by Exception
|
45
|
+
last_1_hour: Last 1 hour
|
46
|
+
last_24_hours: Last 24 hours
|
47
|
+
last_3_days: Last 3 days
|
48
|
+
last_3_hours: Last 3 hours
|
49
|
+
last_7_days: Last 7 days
|
50
|
+
title: Discard Cleaner
|
51
|
+
total: Total
|
38
52
|
cron_entries:
|
39
53
|
actions:
|
40
54
|
confirm_disable: Tem certeza de que deseja desativar esta tarefa programada?
|
@@ -236,6 +250,7 @@ pt-BR:
|
|
236
250
|
search: Pesquisar
|
237
251
|
navbar:
|
238
252
|
batches: Lotes
|
253
|
+
cleaner: Discard Cleaner
|
239
254
|
cron_schedules: Agendamentos
|
240
255
|
jobs: Tarefas
|
241
256
|
live_poll: Acompanhamento ao Vivo
|
data/config/locales/ru.yml
CHANGED
@@ -35,6 +35,20 @@ ru:
|
|
35
35
|
callback_jobs: Коллбеки
|
36
36
|
table:
|
37
37
|
no_batches_found: Группы заданий не найдены.
|
38
|
+
cleaner:
|
39
|
+
index:
|
40
|
+
all: All
|
41
|
+
class: Class
|
42
|
+
exception: Exception
|
43
|
+
grouped_by_class: Discards grouped by Class
|
44
|
+
grouped_by_exception: Discards grouped by Exception
|
45
|
+
last_1_hour: Last 1 hour
|
46
|
+
last_24_hours: Last 24 hours
|
47
|
+
last_3_days: Last 3 days
|
48
|
+
last_3_hours: Last 3 hours
|
49
|
+
last_7_days: Last 7 days
|
50
|
+
title: Discard Cleaner
|
51
|
+
total: Total
|
38
52
|
cron_entries:
|
39
53
|
actions:
|
40
54
|
confirm_disable: Вы уверены, что хотите отключить эту задачу cron?
|
@@ -262,6 +276,7 @@ ru:
|
|
262
276
|
search: Поиск
|
263
277
|
navbar:
|
264
278
|
batches: Пакетные задания
|
279
|
+
cleaner: Discard Cleaner
|
265
280
|
cron_schedules: Cron
|
266
281
|
jobs: Задания
|
267
282
|
live_poll: Обновления в реальном времени
|
data/config/locales/tr.yml
CHANGED
@@ -35,6 +35,20 @@ tr:
|
|
35
35
|
callback_jobs: Geri Çağırma İşleri
|
36
36
|
table:
|
37
37
|
no_batches_found: Toplu İşlem bulunamadı.
|
38
|
+
cleaner:
|
39
|
+
index:
|
40
|
+
all: All
|
41
|
+
class: Class
|
42
|
+
exception: Exception
|
43
|
+
grouped_by_class: Discards grouped by Class
|
44
|
+
grouped_by_exception: Discards grouped by Exception
|
45
|
+
last_1_hour: Last 1 hour
|
46
|
+
last_24_hours: Last 24 hours
|
47
|
+
last_3_days: Last 3 days
|
48
|
+
last_3_hours: Last 3 hours
|
49
|
+
last_7_days: Last 7 days
|
50
|
+
title: Discard Cleaner
|
51
|
+
total: Total
|
38
52
|
cron_entries:
|
39
53
|
actions:
|
40
54
|
confirm_disable: Bu cron girişini devre dışı bırakmak istediğinizden emin misiniz?
|
@@ -236,6 +250,7 @@ tr:
|
|
236
250
|
search: Ara
|
237
251
|
navbar:
|
238
252
|
batches: Toplu İşler
|
253
|
+
cleaner: Discard Cleaner
|
239
254
|
cron_schedules: Cron
|
240
255
|
jobs: İşler
|
241
256
|
live_poll: Anlık Güncelleme
|
data/config/locales/uk.yml
CHANGED
@@ -35,6 +35,20 @@ uk:
|
|
35
35
|
callback_jobs: Задачі з зворотнім викликом
|
36
36
|
table:
|
37
37
|
no_batches_found: Пакети не знайдені.
|
38
|
+
cleaner:
|
39
|
+
index:
|
40
|
+
all: All
|
41
|
+
class: Class
|
42
|
+
exception: Exception
|
43
|
+
grouped_by_class: Discards grouped by Class
|
44
|
+
grouped_by_exception: Discards grouped by Exception
|
45
|
+
last_1_hour: Last 1 hour
|
46
|
+
last_24_hours: Last 24 hours
|
47
|
+
last_3_days: Last 3 days
|
48
|
+
last_3_hours: Last 3 hours
|
49
|
+
last_7_days: Last 7 days
|
50
|
+
title: Discard Cleaner
|
51
|
+
total: Total
|
38
52
|
cron_entries:
|
39
53
|
actions:
|
40
54
|
confirm_disable: Ви впевнені, що хочете вимкнути цю cron-запис?
|
@@ -262,6 +276,7 @@ uk:
|
|
262
276
|
search: Пошук
|
263
277
|
navbar:
|
264
278
|
batches: Пакети
|
279
|
+
cleaner: Discard Cleaner
|
265
280
|
cron_schedules: Cron
|
266
281
|
jobs: Задачі
|
267
282
|
live_poll: Живе Опитування
|
data/config/routes.rb
CHANGED
@@ -34,8 +34,8 @@ GoodJob::Engine.routes.draw do
|
|
34
34
|
end
|
35
35
|
|
36
36
|
resources :processes, only: %i[index]
|
37
|
-
|
38
37
|
resources :performance, only: %i[index show]
|
38
|
+
resources :cleaner, only: %i[index]
|
39
39
|
|
40
40
|
scope :frontend, controller: :frontends, defaults: { version: GoodJob::VERSION.tr(".", "-") } do
|
41
41
|
get "modules/:version/:id", action: :module, as: :frontend_module, constraints: { format: 'js' }
|
@@ -144,7 +144,7 @@ module GoodJob # :nodoc:
|
|
144
144
|
# Tests whether an active advisory lock has been taken on the record.
|
145
145
|
# @return [Boolean]
|
146
146
|
def advisory_locked?
|
147
|
-
@advisory_locked_connection&.weakref_alive? && @advisory_locked_connection
|
147
|
+
@advisory_locked_connection&.weakref_alive? && @advisory_locked_connection.active?
|
148
148
|
end
|
149
149
|
|
150
150
|
# @!visibility private
|
@@ -26,11 +26,13 @@ module GoodJob # :nodoc:
|
|
26
26
|
end
|
27
27
|
|
28
28
|
# Execution configuration to be scheduled
|
29
|
-
# @return [
|
29
|
+
# @return [Array<CronEntry>]
|
30
30
|
attr_reader :cron_entries
|
31
31
|
|
32
32
|
# @param cron_entries [Array<CronEntry>]
|
33
33
|
# @param start_on_initialize [Boolean]
|
34
|
+
# @param graceful_restart_period [ActiveSupport::Duration, nil]
|
35
|
+
# @param executor [Concurrent::Executor]
|
34
36
|
def initialize(cron_entries = [], start_on_initialize: false, graceful_restart_period: nil, executor: Concurrent.global_io_executor)
|
35
37
|
@executor = executor
|
36
38
|
@running = false
|
@@ -82,16 +84,26 @@ module GoodJob # :nodoc:
|
|
82
84
|
|
83
85
|
# Enqueues a scheduled task
|
84
86
|
# @param cron_entry [CronEntry] the CronEntry object to schedule
|
85
|
-
# @param
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
87
|
+
# @param at [Time, nil] When a task needs to optionally be rescheduled because of clock-drift or other inaccuracy
|
88
|
+
# @param previously_at [Time, nil] the last +in-memory+ scheduled time the cron task was intended to run
|
89
|
+
def create_task(cron_entry, at: nil, previously_at: nil)
|
90
|
+
cron_at = at || cron_entry.next_at(previously_at: previously_at)
|
91
|
+
|
92
|
+
# ScheduledTask runs immediately if delay is <= 0.01; avoid ever scheduling the task before the intended time
|
93
|
+
# https://github.com/ruby-concurrency/concurrent-ruby/blob/56227a4c3ebdd53b8b0976eb8296ceb7a093496f/lib/concurrent-ruby/concurrent/executor/timer_set.rb#L97
|
94
|
+
delay = cron_at <= Time.current ? 0.0 : [(cron_at - Time.current).to_f, 0.02].max
|
95
|
+
|
96
|
+
future = Concurrent::ScheduledTask.new(delay, args: [self, cron_entry, cron_at, previously_at], executor: @executor) do |thr_manager, thr_cron_entry, thr_cron_at|
|
97
|
+
if thr_cron_at && thr_cron_at > Time.current
|
98
|
+
# If clock drift or other inaccuracy, reschedule the task again
|
99
|
+
thr_manager.create_task(thr_cron_entry, at: thr_cron_at, previously_at: previously_at)
|
100
|
+
else
|
101
|
+
# Re-schedule the next cron task before executing the current task
|
102
|
+
thr_manager.create_task(thr_cron_entry, previously_at: thr_cron_at)
|
103
|
+
|
104
|
+
Rails.application.executor.wrap do
|
105
|
+
cron_entry.enqueue(thr_cron_at) if thr_cron_entry.enabled?
|
106
|
+
end
|
95
107
|
end
|
96
108
|
end
|
97
109
|
|
@@ -108,7 +120,7 @@ module GoodJob # :nodoc:
|
|
108
120
|
|
109
121
|
time_period = @graceful_restart_period.ago..Time.current
|
110
122
|
cron_entry.within(time_period).each do |cron_at|
|
111
|
-
future = Concurrent::Future.new(args: [self, cron_entry, cron_at], executor: @executor) do |
|
123
|
+
future = Concurrent::Future.new(args: [self, cron_entry, cron_at], executor: @executor) do |_thr_manager, thr_cron_entry, thr_cron_at|
|
112
124
|
Rails.application.executor.wrap do
|
113
125
|
cron_entry.enqueue(thr_cron_at) if thr_cron_entry.enabled?
|
114
126
|
end
|
data/lib/good_job/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: good_job
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Sheldon
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-11-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|
@@ -254,6 +254,7 @@ files:
|
|
254
254
|
- app/charts/good_job/scheduled_by_queue_chart.rb
|
255
255
|
- app/controllers/good_job/application_controller.rb
|
256
256
|
- app/controllers/good_job/batches_controller.rb
|
257
|
+
- app/controllers/good_job/cleaner_controller.rb
|
257
258
|
- app/controllers/good_job/cron_entries_controller.rb
|
258
259
|
- app/controllers/good_job/frontends_controller.rb
|
259
260
|
- app/controllers/good_job/jobs_controller.rb
|
@@ -305,6 +306,7 @@ files:
|
|
305
306
|
- app/views/good_job/batches/_table.erb
|
306
307
|
- app/views/good_job/batches/index.html.erb
|
307
308
|
- app/views/good_job/batches/show.html.erb
|
309
|
+
- app/views/good_job/cleaner/index.html.erb
|
308
310
|
- app/views/good_job/cron_entries/index.html.erb
|
309
311
|
- app/views/good_job/cron_entries/show.html.erb
|
310
312
|
- app/views/good_job/jobs/_executions.erb
|