good_job 3.0.0 → 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 +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
|