good_job 3.0.2 → 3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/app/controllers/good_job/jobs_controller.rb +1 -1
- data/app/views/good_job/jobs/_executions.erb +1 -1
- data/app/views/good_job/jobs/_table.erb +2 -2
- data/app/views/good_job/jobs/show.html.erb +1 -1
- data/app/views/good_job/shared/_filter.erb +1 -1
- data/app/views/good_job/shared/_navbar.erb +15 -3
- data/config/locales/en.yml +19 -0
- data/config/locales/es.yml +19 -0
- data/config/locales/nl.yml +19 -0
- data/config/locales/ru.yml +19 -0
- data/lib/good_job/version.rb +1 -1
- data/lib/models/good_job/cron_entry.rb +4 -2
- data/lib/models/good_job/execution.rb +30 -4
- data/lib/models/good_job/job.rb +57 -7
- data/lib/models/good_job/process.rb +2 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc6e3cffa2189a101181b7ceb278de97ded27d14dd6da915ea8fe3729907dd88
|
4
|
+
data.tar.gz: 0504d2f2efd09d1d52669597e364f62b69edc739d3c76b8bcfdd1933ea7cb8da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c10f675a3635f481e370502828ed0902aff3464e19f161bf5f300463a2671ecac09643eb0943030eda30163171b67986b0f9e31ca423ad5da9e4ffd5b23a7df7
|
7
|
+
data.tar.gz: 3ab12e91adb910040a4007140054cc048a0f83e34e54ee649e52ea673a27b95cfb267b56fae98a7605616e4c3f55d17af403c99bf9ba2a5d504dffdd917a7cbb
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,29 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v3.1.0](https://github.com/bensheldon/good_job/tree/v3.1.0) (2022-07-11)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.0.2...v3.1.0)
|
6
|
+
|
7
|
+
**Implemented enhancements:**
|
8
|
+
|
9
|
+
- Improve Dashboard display of parameters \(CronEntry kwargs; Process configuration; Job and Execution database values\) [\#662](https://github.com/bensheldon/good_job/pull/662) ([bensheldon](https://github.com/bensheldon))
|
10
|
+
|
11
|
+
**Fixed bugs:**
|
12
|
+
|
13
|
+
- Don't delegate `GoodJob::Job#status` to executions to avoid race condition [\#661](https://github.com/bensheldon/good_job/pull/661) ([bensheldon](https://github.com/bensheldon))
|
14
|
+
|
15
|
+
**Closed issues:**
|
16
|
+
|
17
|
+
- How to suppress repetitive logs in development? [\#658](https://github.com/bensheldon/good_job/issues/658)
|
18
|
+
- 500 Internal Server Error Exception in web interface trying to view running jobs [\#656](https://github.com/bensheldon/good_job/issues/656)
|
19
|
+
- Cron schedule page in dashboard not showing kwargs [\#608](https://github.com/bensheldon/good_job/issues/608)
|
20
|
+
- Paralelism x database connections [\#569](https://github.com/bensheldon/good_job/issues/569)
|
21
|
+
|
22
|
+
**Merged pull requests:**
|
23
|
+
|
24
|
+
- Show job/cron/process counts in the Navbar [\#663](https://github.com/bensheldon/good_job/pull/663) ([bensheldon](https://github.com/bensheldon))
|
25
|
+
- Dequeing should be first-in first-out [\#651](https://github.com/bensheldon/good_job/pull/651) ([jrochkind](https://github.com/jrochkind))
|
26
|
+
|
3
27
|
## [v3.0.2](https://github.com/bensheldon/good_job/tree/v3.0.2) (2022-07-10)
|
4
28
|
|
5
29
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.0.1...v3.0.2)
|
@@ -38,7 +38,7 @@
|
|
38
38
|
</div>
|
39
39
|
<% end %>
|
40
40
|
<div>
|
41
|
-
<%= tag.pre JSON.pretty_generate(execution.
|
41
|
+
<%= tag.pre JSON.pretty_generate(execution.display_serialized_params), id: dom_id(execution, "params"), class: "collapse bg-light card card-body p-3 my-3" %>
|
42
42
|
</div>
|
43
43
|
<% end %>
|
44
44
|
<% end %>
|
@@ -13,7 +13,7 @@
|
|
13
13
|
<th>Executions</th>
|
14
14
|
<th>Error</th>
|
15
15
|
<th>
|
16
|
-
|
16
|
+
Parameters
|
17
17
|
<%= tag.button "Toggle", type: "button", class: "btn btn-sm btn-outline-primary", role: "button",
|
18
18
|
data: { bs_toggle: "collapse", bs_target: ".job-params" },
|
19
19
|
aria: { expanded: false, controls: jobs.map { |job| "##{dom_id(job, "params")}" }.join(" ") }
|
@@ -71,7 +71,7 @@
|
|
71
71
|
data: { bs_toggle: "collapse", bs_target: "##{dom_id(job, 'params')}" },
|
72
72
|
aria: { expanded: false, controls: dom_id(job, "params") }
|
73
73
|
%>
|
74
|
-
<%= tag.pre JSON.pretty_generate(job.
|
74
|
+
<%= tag.pre JSON.pretty_generate(job.display_serialized_params), id: dom_id(job, "params"), class: "collapse job-params" %>
|
75
75
|
</td>
|
76
76
|
<td>
|
77
77
|
<div class="text-nowrap">
|
@@ -11,7 +11,7 @@
|
|
11
11
|
<li class="nav-item">
|
12
12
|
<%= link_to url_for({state: name}), class: "nav-link #{"active" if params[:state] == name}" do %>
|
13
13
|
<%= t(name, scope: 'good_job.status') %>
|
14
|
-
<span class="badge bg-primary rounded-pill <%= "bg-secondary" if count == 0 %>"><%= count %></span>
|
14
|
+
<span class="badge bg-primary rounded-pill <%= "bg-secondary" if count == 0 %>"><%= number_with_delimiter(count) %></span>
|
15
15
|
<% end %>
|
16
16
|
</li>
|
17
17
|
<% end %>
|
@@ -8,13 +8,25 @@
|
|
8
8
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
9
9
|
<ul class="navbar-nav me-auto">
|
10
10
|
<li class="nav-item">
|
11
|
-
<%= link_to
|
11
|
+
<%= link_to jobs_path, class: ["nav-link", ("active" if controller_name == 'jobs')] do %>
|
12
|
+
<%= t(".jobs") %>
|
13
|
+
<% jobs_count = GoodJob::Job.count %>
|
14
|
+
<span class="badge bg-secondary rounded-pill"><%= number_to_human(jobs_count) %></span>
|
15
|
+
<% end %>
|
12
16
|
</li>
|
13
17
|
<li class="nav-item">
|
14
|
-
<%= link_to
|
18
|
+
<%= link_to cron_entries_path, class: ["nav-link", ("active" if controller_name == 'cron_entries')] do %>
|
19
|
+
<%= t(".cron_schedules") %>
|
20
|
+
<% cron_entries_count = GoodJob::CronEntry.all.size %>
|
21
|
+
<span class="badge bg-secondary rounded-pill"><%= cron_entries_count %></span>
|
22
|
+
<% end %>
|
15
23
|
</li>
|
16
24
|
<li class="nav-item">
|
17
|
-
<%= link_to
|
25
|
+
<%= link_to processes_path, class: ["nav-link", ("active" if controller_name == 'processes')] do %>
|
26
|
+
<%= t(".processes") %>
|
27
|
+
<% processes_count = GoodJob::Process.count %>
|
28
|
+
<span class="badge bg-secondary rounded-pill <%= "bg-danger" if processes_count == 0 %>"><%= processes_count %></span>
|
29
|
+
<% end %>
|
18
30
|
</li>
|
19
31
|
</ul>
|
20
32
|
<div class="nav-item pe-2">
|
data/config/locales/en.yml
CHANGED
@@ -63,3 +63,22 @@ en:
|
|
63
63
|
retried: Retried
|
64
64
|
running: Running
|
65
65
|
scheduled: Scheduled
|
66
|
+
number:
|
67
|
+
format:
|
68
|
+
delimiter: ","
|
69
|
+
separator: "."
|
70
|
+
human:
|
71
|
+
decimal_units:
|
72
|
+
format: "%n%u"
|
73
|
+
units:
|
74
|
+
billion: B
|
75
|
+
hundred: ''
|
76
|
+
million: M
|
77
|
+
quadrillion: Q
|
78
|
+
thousand: K
|
79
|
+
trillion: T
|
80
|
+
unit: ''
|
81
|
+
format:
|
82
|
+
delimiter: ","
|
83
|
+
precision: 3
|
84
|
+
separator: "."
|
data/config/locales/es.yml
CHANGED
@@ -63,3 +63,22 @@ es:
|
|
63
63
|
retried: reintentado
|
64
64
|
running: Corriendo
|
65
65
|
scheduled: Programado
|
66
|
+
number:
|
67
|
+
format:
|
68
|
+
delimiter: " "
|
69
|
+
separator: ","
|
70
|
+
human:
|
71
|
+
decimal_units:
|
72
|
+
format: "%n%u"
|
73
|
+
units:
|
74
|
+
billion: B
|
75
|
+
hundred: ''
|
76
|
+
million: M
|
77
|
+
quadrillion: q
|
78
|
+
thousand: k
|
79
|
+
trillion: T
|
80
|
+
unit: ''
|
81
|
+
format:
|
82
|
+
delimiter: " "
|
83
|
+
precision: 3
|
84
|
+
separator: ","
|
data/config/locales/nl.yml
CHANGED
@@ -63,3 +63,22 @@ nl:
|
|
63
63
|
retried: Opnieuw geprobeerd
|
64
64
|
running: Rennen
|
65
65
|
scheduled: Gepland
|
66
|
+
number:
|
67
|
+
format:
|
68
|
+
delimiter: "."
|
69
|
+
separator: ","
|
70
|
+
human:
|
71
|
+
decimal_units:
|
72
|
+
format: "%n%u"
|
73
|
+
units:
|
74
|
+
billion: B
|
75
|
+
hundred: ''
|
76
|
+
million: M
|
77
|
+
quadrillion: Q
|
78
|
+
thousand: K
|
79
|
+
trillion: T
|
80
|
+
unit: ''
|
81
|
+
format:
|
82
|
+
delimiter: "."
|
83
|
+
precision: 3
|
84
|
+
separator: ","
|
data/config/locales/ru.yml
CHANGED
@@ -87,3 +87,22 @@ ru:
|
|
87
87
|
retried: Повторная попытка
|
88
88
|
running: Бег
|
89
89
|
scheduled: по расписанию
|
90
|
+
number:
|
91
|
+
format:
|
92
|
+
delimiter: " "
|
93
|
+
separator: ","
|
94
|
+
human:
|
95
|
+
decimal_units:
|
96
|
+
format: "%n%u"
|
97
|
+
units:
|
98
|
+
billion: Б
|
99
|
+
hundred: ''
|
100
|
+
million: М
|
101
|
+
quadrillion: Q
|
102
|
+
thousand: К
|
103
|
+
trillion: Т
|
104
|
+
unit: ''
|
105
|
+
format:
|
106
|
+
delimiter: " "
|
107
|
+
precision: 3
|
108
|
+
separator: ","
|
data/lib/good_job/version.rb
CHANGED
@@ -112,9 +112,11 @@ module GoodJob # :nodoc:
|
|
112
112
|
class: job_class,
|
113
113
|
cron: schedule,
|
114
114
|
set: display_property(set),
|
115
|
-
args: display_property(args),
|
116
115
|
description: display_property(description),
|
117
|
-
}
|
116
|
+
}.tap do |properties|
|
117
|
+
properties[:args] = display_property(args) if args.present?
|
118
|
+
properties[:kwargs] = display_property(kwargs) if kwargs.present?
|
119
|
+
end
|
118
120
|
end
|
119
121
|
|
120
122
|
private
|
@@ -88,6 +88,18 @@ module GoodJob
|
|
88
88
|
# @return [ActiveRecord::Relation]
|
89
89
|
scope :priority_ordered, -> { order('priority DESC NULLS LAST') }
|
90
90
|
|
91
|
+
# Order jobs by created_at, for first-in first-out
|
92
|
+
# @!method creation_ordered
|
93
|
+
# @!scope class
|
94
|
+
# @return [ActiveRecord:Relation]
|
95
|
+
scope :creation_ordered, -> { order('created_at ASC') }
|
96
|
+
|
97
|
+
# Order jobs for de-queueing
|
98
|
+
# @!method dequeue_ordered
|
99
|
+
# @!scope class
|
100
|
+
# @return [ActiveRecord:Relation]
|
101
|
+
scope :dequeue_ordered, -> { priority_ordered.creation_ordered }
|
102
|
+
|
91
103
|
# Order jobs by scheduled or created (oldest first).
|
92
104
|
# @!method schedule_ordered
|
93
105
|
# @!scope class
|
@@ -154,7 +166,7 @@ module GoodJob
|
|
154
166
|
# raised, if any (if the job raised, then the second array entry will be
|
155
167
|
# +nil+). If there were no jobs to execute, returns +nil+.
|
156
168
|
def self.perform_with_advisory_lock
|
157
|
-
unfinished.
|
169
|
+
unfinished.dequeue_ordered.only_scheduled.limit(1).with_advisory_lock(unlock_session: true) do |executions|
|
158
170
|
execution = executions.first
|
159
171
|
break if execution.blank?
|
160
172
|
break :unlocked unless execution&.executable?
|
@@ -279,7 +291,9 @@ module GoodJob
|
|
279
291
|
# @return [Symbol]
|
280
292
|
def status
|
281
293
|
if finished_at.present?
|
282
|
-
if error.present?
|
294
|
+
if error.present? && retried_good_job_id.present?
|
295
|
+
:retried
|
296
|
+
elsif error.present? && retried_good_job_id.nil?
|
283
297
|
:discarded
|
284
298
|
else
|
285
299
|
:finished
|
@@ -297,8 +311,20 @@ module GoodJob
|
|
297
311
|
end
|
298
312
|
end
|
299
313
|
|
314
|
+
# Return formatted serialized_params for display in the dashboard
|
315
|
+
# @return [Hash]
|
316
|
+
def display_serialized_params
|
317
|
+
serialized_params.merge({
|
318
|
+
_good_job: attributes.except('serialized_params', 'locktype', 'owns_advisory_lock'),
|
319
|
+
})
|
320
|
+
end
|
321
|
+
|
300
322
|
def running?
|
301
|
-
|
323
|
+
if has_attribute?(:locktype)
|
324
|
+
self['locktype'].present?
|
325
|
+
else
|
326
|
+
advisory_locked?
|
327
|
+
end
|
302
328
|
end
|
303
329
|
|
304
330
|
def number
|
@@ -314,7 +340,7 @@ module GoodJob
|
|
314
340
|
def queue_latency
|
315
341
|
now = Time.zone.now
|
316
342
|
expected_start = scheduled_at || created_at
|
317
|
-
actual_start = performed_at || now
|
343
|
+
actual_start = performed_at || finished_at || now
|
318
344
|
|
319
345
|
actual_start - expected_start unless expected_start >= now
|
320
346
|
end
|
data/lib/models/good_job/job.rb
CHANGED
@@ -3,7 +3,8 @@ module GoodJob
|
|
3
3
|
# ActiveRecord model that represents an +ActiveJob+ job.
|
4
4
|
# There is not a table in the database whose discrete rows represents "Jobs".
|
5
5
|
# The +good_jobs+ table is a table of individual {GoodJob::Execution}s that share the same +active_job_id+.
|
6
|
-
# A single row from the +good_jobs+ table of executions is fetched to represent
|
6
|
+
# A single row from the +good_jobs+ table of executions is fetched to represent a Job.
|
7
|
+
#
|
7
8
|
class Job < BaseRecord
|
8
9
|
include Filterable
|
9
10
|
include Lockable
|
@@ -72,9 +73,51 @@ module GoodJob
|
|
72
73
|
serialized_params['job_class']
|
73
74
|
end
|
74
75
|
|
75
|
-
|
76
|
-
|
77
|
-
|
76
|
+
def last_status_at
|
77
|
+
finished_at || performed_at || scheduled_at || created_at
|
78
|
+
end
|
79
|
+
|
80
|
+
def status
|
81
|
+
if finished_at.present?
|
82
|
+
if error.present? && retried_good_job_id.present?
|
83
|
+
:retried
|
84
|
+
elsif error.present? && retried_good_job_id.nil?
|
85
|
+
:discarded
|
86
|
+
else
|
87
|
+
:finished
|
88
|
+
end
|
89
|
+
elsif (scheduled_at || created_at) > DateTime.current
|
90
|
+
if serialized_params.fetch('executions', 0) > 1
|
91
|
+
:retried
|
92
|
+
else
|
93
|
+
:scheduled
|
94
|
+
end
|
95
|
+
elsif running?
|
96
|
+
:running
|
97
|
+
else
|
98
|
+
:queued
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Override #reload to add a custom scope to ensure the reloaded record is the head execution
|
103
|
+
# @return [Job]
|
104
|
+
def reload(options = nil)
|
105
|
+
self.class.connection.clear_query_cache
|
106
|
+
|
107
|
+
# override with the `where(retried_good_job_id: nil)` scope
|
108
|
+
override_query = self.class.where(retried_good_job_id: nil)
|
109
|
+
fresh_object =
|
110
|
+
if options && options[:lock]
|
111
|
+
self.class.unscoped { override_query.lock(options[:lock]).find(id) }
|
112
|
+
else
|
113
|
+
self.class.unscoped { override_query.find(id) }
|
114
|
+
end
|
115
|
+
|
116
|
+
@attributes = fresh_object.instance_variable_get(:@attributes)
|
117
|
+
@new_record = false
|
118
|
+
@previously_new_record = false
|
119
|
+
self
|
120
|
+
end
|
78
121
|
|
79
122
|
# This job's most recent {Execution}
|
80
123
|
# @param reload [Booelan] whether to reload executions
|
@@ -94,7 +137,7 @@ module GoodJob
|
|
94
137
|
# The number of times this job has been executed, according to ActiveJob's serialized state.
|
95
138
|
# @return [Numeric]
|
96
139
|
def executions_count
|
97
|
-
aj_count =
|
140
|
+
aj_count = serialized_params.fetch('executions', 0)
|
98
141
|
# The execution count within serialized_params is not updated
|
99
142
|
# once the underlying execution has been executed.
|
100
143
|
if status.in? [:discarded, :finished, :running]
|
@@ -114,7 +157,15 @@ module GoodJob
|
|
114
157
|
# If the job has been retried, the error will be fetched from the previous {Execution} record.
|
115
158
|
# @return [String]
|
116
159
|
def recent_error
|
117
|
-
|
160
|
+
error || executions[-2]&.error
|
161
|
+
end
|
162
|
+
|
163
|
+
# Return formatted serialized_params for display in the dashboard
|
164
|
+
# @return [Hash]
|
165
|
+
def display_serialized_params
|
166
|
+
serialized_params.merge({
|
167
|
+
_good_job: attributes.except('serialized_params', 'locktype', 'owns_advisory_lock'),
|
168
|
+
})
|
118
169
|
end
|
119
170
|
|
120
171
|
# Tests whether the job is being executed right now.
|
@@ -192,7 +243,6 @@ module GoodJob
|
|
192
243
|
|
193
244
|
raise ActionForStateMismatchError if execution.finished_at.present?
|
194
245
|
|
195
|
-
execution = head_execution(reload: true)
|
196
246
|
execution.update(scheduled_at: scheduled_at)
|
197
247
|
end
|
198
248
|
end
|
@@ -45,6 +45,8 @@ module GoodJob # :nodoc:
|
|
45
45
|
hostname: Socket.gethostname,
|
46
46
|
pid: ::Process.pid,
|
47
47
|
proctitle: $PROGRAM_NAME,
|
48
|
+
preserve_job_records: GoodJob.preserve_job_records,
|
49
|
+
retry_on_unhandled_error: GoodJob.retry_on_unhandled_error,
|
48
50
|
schedulers: GoodJob::Scheduler.instances.map(&:name),
|
49
51
|
}
|
50
52
|
end
|
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: 3.0
|
4
|
+
version: 3.1.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: 2022-07-
|
11
|
+
date: 2022-07-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|