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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a4f4e14bae83760bdeb35557a727116d053e47a9b7dbf501914606dbc45c2ef7
4
- data.tar.gz: c06e9165b7ac5d87af0ab75291fedd0194018752f34332c1a16930ddca53e3dd
3
+ metadata.gz: bc6e3cffa2189a101181b7ceb278de97ded27d14dd6da915ea8fe3729907dd88
4
+ data.tar.gz: 0504d2f2efd09d1d52669597e364f62b69edc739d3c76b8bcfdd1933ea7cb8da
5
5
  SHA512:
6
- metadata.gz: 949cfcf1506ff658666113e035a875ed4ab44fa3e2c674e4d5d1440bf484d39793a1ee595ae0cb6f719136ce5541aae09a7fc2d66a049ea1bcf973b0165dc8a4
7
- data.tar.gz: 9c9ff56251e01d60823a50f4edcea74034a36ef93929cf59adc588273da86d1e04f67c1b25d7d35efecda9309acf7f49f81d29fbc7f94249be0e3732087f9081
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 + (ENV.fetch("GOOD_JOB_MAX_THREADS", 5).to_i %>
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:
@@ -56,7 +56,7 @@ module GoodJob
56
56
  end
57
57
 
58
58
  def show
59
- @job = Job.find(params[:id])
59
+ @job = Job.includes_advisory_locks.find(params[:id])
60
60
  end
61
61
 
62
62
  def discard
@@ -38,7 +38,7 @@
38
38
  </div>
39
39
  <% end %>
40
40
  <div>
41
- <%= tag.pre JSON.pretty_generate(execution.serialized_params), id: dom_id(execution, "params"), class: "collapse bg-light card card-body p-3 my-3" %>
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
- ActiveJob Params&nbsp;
16
+ Parameters&nbsp;
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.serialized_params), id: dom_id(job, "params"), class: "collapse job-params" %>
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">
@@ -54,4 +54,4 @@
54
54
  <%= tag.pre @job.serialized_params["arguments"].map(&:inspect).join(', ') %>
55
55
  </div>
56
56
 
57
- <%= render 'executions', executions: @job.executions.reverse %>
57
+ <%= render 'executions', executions: @job.executions.includes_advisory_locks.reverse %>
@@ -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 t(".jobs"), jobs_path, class: ["nav-link", ("active" if controller_name == 'jobs')] %>
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 t(".cron_schedules"), cron_entries_path, class: ["nav-link", ("active" if controller_name == 'cron_entries')] %>
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 t(".processes"), processes_path, class: ["nav-link", ("active" if controller_name == 'processes')] %>
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">
@@ -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: "."
@@ -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: ","
@@ -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: ","
@@ -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
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module GoodJob
3
3
  # GoodJob gem version.
4
- VERSION = '3.0.0'
4
+ VERSION = '3.1.0'
5
5
  end
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).destroy_all
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.priority_ordered.only_scheduled.limit(1).with_advisory_lock(unlock_session: true) do |executions|
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
- performed_at? && !finished_at?
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
 
@@ -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 an Job
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
- # The status of the Job, based on the state of its most recent execution.
76
- # @return [Symbol]
77
- delegate :status, :last_status_at, to: :head_execution
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 = head_execution.serialized_params.fetch('executions', 0)
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
- head_execution.error || executions[-2]&.error
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.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-06-26 00:00:00.000000000 Z
11
+ date: 2022-07-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob