good_job 3.0.0 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +62 -1
- data/README.md +11 -1
- 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/active_job_extensions/concurrency.rb +20 -0
- data/lib/good_job/version.rb +1 -1
- data/lib/good_job.rb +1 -1
- data/lib/models/good_job/cron_entry.rb +4 -2
- data/lib/models/good_job/execution.rb +31 -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,67 @@
|
|
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
|
+
|
27
|
+
## [v3.0.2](https://github.com/bensheldon/good_job/tree/v3.0.2) (2022-07-10)
|
28
|
+
|
29
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.0.1...v3.0.2)
|
30
|
+
|
31
|
+
**Fixed bugs:**
|
32
|
+
|
33
|
+
- Copy forward concurrency key value when retrying a job, rather than regenerating it [\#622](https://github.com/bensheldon/good_job/issues/622)
|
34
|
+
- All concurrency controlled jobs throw exceptions and are rescheduled if they are called using perform\_now [\#591](https://github.com/bensheldon/good_job/issues/591)
|
35
|
+
|
36
|
+
**Closed issues:**
|
37
|
+
|
38
|
+
- Queue config not respecting limits [\#659](https://github.com/bensheldon/good_job/issues/659)
|
39
|
+
- UI engine does not work without explicit require [\#646](https://github.com/bensheldon/good_job/issues/646)
|
40
|
+
- Should `:inline` adapter mode retry jobs? [\#611](https://github.com/bensheldon/good_job/issues/611)
|
41
|
+
- Error Job Not Preserved [\#594](https://github.com/bensheldon/good_job/issues/594)
|
42
|
+
- Jobs never get run... [\#516](https://github.com/bensheldon/good_job/issues/516)
|
43
|
+
- Release GoodJob 3.0 [\#507](https://github.com/bensheldon/good_job/issues/507)
|
44
|
+
- Improve security of Gem releases [\#422](https://github.com/bensheldon/good_job/issues/422)
|
45
|
+
|
46
|
+
**Merged pull requests:**
|
47
|
+
|
48
|
+
- Preserve initial concurrency key when retrying jobs [\#657](https://github.com/bensheldon/good_job/pull/657) ([bensheldon](https://github.com/bensheldon))
|
49
|
+
- Add Dashboard troubleshooting note to explicitly require the engine [\#654](https://github.com/bensheldon/good_job/pull/654) ([bensheldon](https://github.com/bensheldon))
|
50
|
+
- Removes wrong parentheses [\#653](https://github.com/bensheldon/good_job/pull/653) ([esasse](https://github.com/esasse))
|
51
|
+
|
52
|
+
## [v3.0.1](https://github.com/bensheldon/good_job/tree/v3.0.1) (2022-07-02)
|
53
|
+
|
54
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.0.0...v3.0.1)
|
55
|
+
|
56
|
+
**Closed issues:**
|
57
|
+
|
58
|
+
- ERROR: relation "good\_jobs" does not exist at character 454 [\#308](https://github.com/bensheldon/good_job/issues/308)
|
59
|
+
|
60
|
+
**Merged pull requests:**
|
61
|
+
|
62
|
+
- Fix `GoodJob.cleanup_preserved_jobs` to use `delete_all` instead of `destroy_all` [\#652](https://github.com/bensheldon/good_job/pull/652) ([bensheldon](https://github.com/bensheldon))
|
63
|
+
- Create codeql-analysis.yml [\#648](https://github.com/bensheldon/good_job/pull/648) ([bensheldon](https://github.com/bensheldon))
|
64
|
+
|
3
65
|
## [v3.0.0](https://github.com/bensheldon/good_job/tree/v3.0.0) (2022-06-26)
|
4
66
|
|
5
67
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v2.99.0...v3.0.0)
|
@@ -1011,7 +1073,6 @@
|
|
1011
1073
|
|
1012
1074
|
**Closed issues:**
|
1013
1075
|
|
1014
|
-
- ERROR: relation "good\_jobs" does not exist at character 454 [\#308](https://github.com/bensheldon/good_job/issues/308)
|
1015
1076
|
- Add Frozen String Literal to all files [\#298](https://github.com/bensheldon/good_job/issues/298)
|
1016
1077
|
- Support for good\_job without Rails? [\#295](https://github.com/bensheldon/good_job/issues/295)
|
1017
1078
|
|
data/README.md
CHANGED
@@ -370,6 +370,16 @@ GoodJob includes a Dashboard as a mountable `Rails::Engine`.
|
|
370
370
|
|
371
371
|
See more at [Monitor and preserve worked jobs](#monitor-and-preserve-worked-jobs)
|
372
372
|
|
373
|
+
**Troubleshooting the Dashboard:** Some applications are unable to autoload the Goodjob Engine. To work around this, explicitly require the Engine at the top of your `config/application.rb` file, immediately after Rails is required and before Bundler requires the Rails' groups.
|
374
|
+
|
375
|
+
```ruby
|
376
|
+
# config/application.rb
|
377
|
+
require_relative 'boot'
|
378
|
+
require 'rails/all'
|
379
|
+
require 'good_job/engine' # <= Add this line
|
380
|
+
# ...
|
381
|
+
```
|
382
|
+
|
373
383
|
#### API-only Rails applications
|
374
384
|
|
375
385
|
API-only Rails applications may not have all of the required Rack middleware for the GoodJob Dashboard to function. To re-add the middlware:
|
@@ -713,7 +723,7 @@ Each GoodJob execution thread requires its own database connection that is autom
|
|
713
723
|
|
714
724
|
```yaml
|
715
725
|
# config/database.yml
|
716
|
-
pool: <%= ENV.fetch("RAILS_MAX_THREADS", 5).to_i + 3 +
|
726
|
+
pool: <%= ENV.fetch("RAILS_MAX_THREADS", 5).to_i + 3 + ENV.fetch("GOOD_JOB_MAX_THREADS", 5).to_i %>
|
717
727
|
```
|
718
728
|
|
719
729
|
To calculate the total number of the database connections you'll need:
|
@@ -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: ","
|
@@ -10,8 +10,18 @@ module GoodJob
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
+
module Prepends
|
14
|
+
def deserialize(job_data)
|
15
|
+
super
|
16
|
+
self.good_job_concurrency_key = job_data['good_job_concurrency_key']
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
13
20
|
included do
|
21
|
+
prepend Prepends
|
22
|
+
|
14
23
|
class_attribute :good_job_concurrency_config, instance_accessor: false, default: {}
|
24
|
+
attr_writer :good_job_concurrency_key
|
15
25
|
|
16
26
|
around_enqueue do |job, block|
|
17
27
|
# Don't attempt to enforce concurrency limits with other queue adapters.
|
@@ -27,6 +37,8 @@ module GoodJob
|
|
27
37
|
(total_limit.present? && (0...Float::INFINITY).cover?(total_limit))
|
28
38
|
next(block.call) unless has_limit
|
29
39
|
|
40
|
+
# Only generate the concurrency key on the initial enqueue in case it is dynamic
|
41
|
+
job.good_job_concurrency_key ||= job._good_job_concurrency_key
|
30
42
|
key = job.good_job_concurrency_key
|
31
43
|
next(block.call) if key.blank?
|
32
44
|
|
@@ -80,7 +92,15 @@ module GoodJob
|
|
80
92
|
end
|
81
93
|
end
|
82
94
|
|
95
|
+
# Existing or dynamically generated concurrency key
|
96
|
+
# @return [Object] concurrency key
|
83
97
|
def good_job_concurrency_key
|
98
|
+
@good_job_concurrency_key || _good_job_concurrency_key
|
99
|
+
end
|
100
|
+
|
101
|
+
# Generates the concurrency key from the configuration
|
102
|
+
# @return [Object] concurrency key
|
103
|
+
def _good_job_concurrency_key
|
84
104
|
key = self.class.good_job_concurrency_config[:key]
|
85
105
|
return if key.blank?
|
86
106
|
|
data/lib/good_job/version.rb
CHANGED
data/lib/good_job.rb
CHANGED
@@ -145,7 +145,7 @@ module GoodJob
|
|
145
145
|
old_jobs = old_jobs.not_discarded unless include_discarded
|
146
146
|
old_jobs_count = old_jobs.count
|
147
147
|
|
148
|
-
GoodJob::Execution.where(job: old_jobs).
|
148
|
+
GoodJob::Execution.where(job: old_jobs).delete_all
|
149
149
|
payload[:destroyed_records_count] = old_jobs_count
|
150
150
|
end
|
151
151
|
end
|
@@ -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
|
@@ -330,6 +356,7 @@ module GoodJob
|
|
330
356
|
serialized_params.deep_dup
|
331
357
|
.tap do |job_data|
|
332
358
|
job_data["provider_job_id"] = id
|
359
|
+
job_data["good_job_concurrency_key"] = concurrency_key if concurrency_key
|
333
360
|
end
|
334
361
|
end
|
335
362
|
|
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.
|
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-
|
11
|
+
date: 2022-07-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|