good_job 4.2.0 → 4.3.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 +34 -0
- data/README.md +10 -10
- data/app/controllers/good_job/jobs_controller.rb +7 -1
- data/app/models/good_job/base_record.rb +1 -0
- data/app/models/good_job/batch.rb +10 -2
- data/app/models/good_job/batch_record.rb +21 -5
- data/app/models/good_job/job.rb +2 -0
- data/config/routes.rb +1 -1
- data/lib/generators/good_job/templates/install/migrations/create_good_jobs.rb.erb +1 -0
- data/lib/generators/good_job/templates/update/migrations/02_add_jobs_finished_at_to_good_job_batches.rb.erb +17 -0
- data/lib/good_job/adapter.rb +1 -1
- data/lib/good_job/version.rb +1 -1
- data/lib/good_job.rb +4 -4
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec5d4c89f52824a8023774ca2179f67579c21ae7772737a367ee912bc58db9bd
|
4
|
+
data.tar.gz: f8526687220d9bd8ec7222f897f2302ab7d42f8883627c43195390b7ab9cf0be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3760a509091f29ca67d90366b06940cb4b12428bbe99a5fd451315ec9895291d2083168603f1f81a3b87ccf1a6df9bcf657d9c89a811768436fdd6a80aa60737
|
7
|
+
data.tar.gz: 9ca52b976c7399f386e141c7ea6d54bfbf3b1b8036ef6f1ac37cc24dede46966ab7644c1c8a5bcde491c3a768862fd1edbd66b7054e06a0e6955e5f7b3d8245f
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,39 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v4.3.0](https://github.com/bensheldon/good_job/tree/v4.3.0) (2024-09-14)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v4.2.1...v4.3.0)
|
6
|
+
|
7
|
+
**Fixed bugs:**
|
8
|
+
|
9
|
+
- Don't shadow gem loading errors during autoloading with the inline adapter [\#1486](https://github.com/bensheldon/good_job/pull/1486) ([Earlopain](https://github.com/Earlopain))
|
10
|
+
- Ensure before actions run on root route [\#1482](https://github.com/bensheldon/good_job/pull/1482) ([ebiven](https://github.com/ebiven))
|
11
|
+
|
12
|
+
**Closed issues:**
|
13
|
+
|
14
|
+
- Undefined method `unhandled_error` for nil [\#1485](https://github.com/bensheldon/good_job/issues/1485)
|
15
|
+
- bin/rails g good\_job:install fails [\#1481](https://github.com/bensheldon/good_job/issues/1481)
|
16
|
+
- Rails 7.2.1 breaks enqueuing without enqueue\_after\_transaction\_commit? method on queue adapter [\#1477](https://github.com/bensheldon/good_job/issues/1477)
|
17
|
+
|
18
|
+
**Merged pull requests:**
|
19
|
+
|
20
|
+
- Fix documentation for 2nd Batch callback parameter: consistently call it `context` [\#1476](https://github.com/bensheldon/good_job/pull/1476) ([martijnversluis](https://github.com/martijnversluis))
|
21
|
+
- Redefine `Batch#finished_at` to mean all callback jobs have finished too; add `Batch#jobs_finished_at` to allow not deleting batches until all their callback jobs complete [\#1454](https://github.com/bensheldon/good_job/pull/1454) ([bensheldon](https://github.com/bensheldon))
|
22
|
+
|
23
|
+
## [v4.2.1](https://github.com/bensheldon/good_job/tree/v4.2.1) (2024-08-29)
|
24
|
+
|
25
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v4.2.0...v4.2.1)
|
26
|
+
|
27
|
+
**Closed issues:**
|
28
|
+
|
29
|
+
- Issue with active\_record.strict\_loading\_by\_default [\#1474](https://github.com/bensheldon/good_job/issues/1474)
|
30
|
+
|
31
|
+
**Merged pull requests:**
|
32
|
+
|
33
|
+
- fix strict\_loading\_by\_default in BaseRecord [\#1475](https://github.com/bensheldon/good_job/pull/1475) ([emilsosa](https://github.com/emilsosa))
|
34
|
+
- Bump rexml from 3.3.3 to 3.3.6 [\#1473](https://github.com/bensheldon/good_job/pull/1473) ([dependabot[bot]](https://github.com/apps/dependabot))
|
35
|
+
- Bump fugit from 1.11.0 to 1.11.1 [\#1471](https://github.com/bensheldon/good_job/pull/1471) ([dependabot[bot]](https://github.com/apps/dependabot))
|
36
|
+
|
3
37
|
## [v4.2.0](https://github.com/bensheldon/good_job/tree/v4.2.0) (2024-08-16)
|
4
38
|
|
5
39
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v4.1.1...v4.2.0)
|
data/README.md
CHANGED
@@ -681,15 +681,15 @@ Batches track a set of jobs, and enqueue an optional callback job when all of th
|
|
681
681
|
OtherJob.perform_later
|
682
682
|
end
|
683
683
|
|
684
|
-
# When these jobs have finished, it will enqueue your `MyBatchCallbackJob.perform_later(batch,
|
684
|
+
# When these jobs have finished, it will enqueue your `MyBatchCallbackJob.perform_later(batch, context)`
|
685
685
|
class MyBatchCallbackJob < ApplicationJob
|
686
|
-
# Callback jobs must accept a `batch` and `
|
687
|
-
def perform(batch,
|
686
|
+
# Callback jobs must accept a `batch` and `context` argument
|
687
|
+
def perform(batch, context)
|
688
688
|
# The batch object will contain the Batch's properties, which are mutable
|
689
689
|
batch.properties[:user] # => <User id: 1, ...>
|
690
690
|
|
691
|
-
#
|
692
|
-
|
691
|
+
# Context is a hash containing additional context (more may be added in the future)
|
692
|
+
context[:event] # => :finish, :success, :discard
|
693
693
|
end
|
694
694
|
end
|
695
695
|
```
|
@@ -757,19 +757,19 @@ Batch callbacks are Active Job jobs that are enqueued at certain events during t
|
|
757
757
|
- `:success` - Enqueued only when all jobs in the batch have finished and succeeded.
|
758
758
|
- `:discard` - Enqueued immediately the first time a job in the batch is discarded.
|
759
759
|
|
760
|
-
Callback jobs must accept a `batch` and `
|
760
|
+
Callback jobs must accept a `batch` and `context` argument in their `perform` method:
|
761
761
|
|
762
762
|
```ruby
|
763
763
|
class MyBatchCallbackJob < ApplicationJob
|
764
|
-
def perform(batch,
|
764
|
+
def perform(batch, context)
|
765
765
|
# The batch object will contain the Batch's properties
|
766
766
|
batch.properties[:user] # => <User id: 1, ...>
|
767
767
|
# Batches are mutable
|
768
768
|
batch.properties[:user] = User.find(2)
|
769
769
|
batch.save
|
770
770
|
|
771
|
-
#
|
772
|
-
|
771
|
+
# Context is a hash containing additional context (more may be added in the future)
|
772
|
+
context[:event] # => :finish, :success, :discard
|
773
773
|
end
|
774
774
|
end
|
775
775
|
```
|
@@ -811,7 +811,7 @@ class WorkJob < ApplicationJob
|
|
811
811
|
end
|
812
812
|
|
813
813
|
class BatchJob < ApplicationJob
|
814
|
-
def perform(batch,
|
814
|
+
def perform(batch, context)
|
815
815
|
if batch.properties[:stage].nil?
|
816
816
|
batch.enqueue(stage: 1) do
|
817
817
|
WorkJob.perform_later('a')
|
@@ -61,7 +61,7 @@ module GoodJob
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def show
|
64
|
-
@job = Job.includes_advisory_locks.find(params[:id])
|
64
|
+
@job = Job.includes(:executions).includes_advisory_locks.find(params[:id])
|
65
65
|
end
|
66
66
|
|
67
67
|
def discard
|
@@ -94,6 +94,12 @@ module GoodJob
|
|
94
94
|
redirect_to jobs_path, notice: t(".notice")
|
95
95
|
end
|
96
96
|
|
97
|
+
def redirect_to_index
|
98
|
+
# Redirect to the jobs page, maintaining query parameters. This is
|
99
|
+
# necessary to support the `?poll=1` parameter that enables live polling.
|
100
|
+
redirect_to jobs_path(request.query_parameters)
|
101
|
+
end
|
102
|
+
|
97
103
|
private
|
98
104
|
|
99
105
|
def redirect_on_error(exception)
|
@@ -26,10 +26,12 @@ module GoodJob
|
|
26
26
|
:enqueued_at,
|
27
27
|
:finished_at,
|
28
28
|
:discarded_at,
|
29
|
+
:jobs_finished_at,
|
29
30
|
:enqueued?,
|
30
31
|
:finished?,
|
31
32
|
:succeeded?,
|
32
33
|
:discarded?,
|
34
|
+
:jobs_finished?,
|
33
35
|
:description,
|
34
36
|
:description=,
|
35
37
|
:on_finish,
|
@@ -95,8 +97,12 @@ module GoodJob
|
|
95
97
|
record.transaction do
|
96
98
|
record.with_advisory_lock(function: "pg_advisory_xact_lock") do
|
97
99
|
record.enqueued_at_will_change!
|
100
|
+
record.jobs_finished_at_will_change! if GoodJob::BatchRecord.jobs_finished_at_migrated?
|
98
101
|
record.finished_at_will_change!
|
99
|
-
|
102
|
+
|
103
|
+
update_attributes = { discarded_at: nil, finished_at: nil }
|
104
|
+
update_attributes[:jobs_finished_at] = nil if GoodJob::BatchRecord.jobs_finished_at_migrated?
|
105
|
+
record.update!(**update_attributes)
|
100
106
|
end
|
101
107
|
end
|
102
108
|
end
|
@@ -142,7 +148,9 @@ module GoodJob
|
|
142
148
|
buffer = GoodJob::Adapter::InlineBuffer.capture do
|
143
149
|
record.transaction do
|
144
150
|
record.with_advisory_lock(function: "pg_advisory_xact_lock") do
|
145
|
-
|
151
|
+
update_attributes = { discarded_at: nil, finished_at: nil }
|
152
|
+
update_attributes[:jobs_finished_at] = nil if GoodJob::BatchRecord.jobs_finished_at_migrated?
|
153
|
+
record.update!(update_attributes)
|
146
154
|
record.jobs.discarded.each(&:retry_job)
|
147
155
|
record._continue_discard_or_finish(lock: false)
|
148
156
|
end
|
@@ -38,6 +38,10 @@ module GoodJob
|
|
38
38
|
query
|
39
39
|
end)
|
40
40
|
|
41
|
+
def self.jobs_finished_at_migrated?
|
42
|
+
column_names.include?('jobs_finished_at')
|
43
|
+
end
|
44
|
+
|
41
45
|
# Whether the batch has finished and no jobs were discarded
|
42
46
|
# @return [Boolean]
|
43
47
|
def succeeded?
|
@@ -52,22 +56,26 @@ module GoodJob
|
|
52
56
|
attributes.except('serialized_properties').merge(properties: properties)
|
53
57
|
end
|
54
58
|
|
55
|
-
def _continue_discard_or_finish(
|
56
|
-
|
59
|
+
def _continue_discard_or_finish(job = nil, lock: true)
|
60
|
+
job_discarded = job && job.finished_at.present? && job.error.present?
|
57
61
|
buffer = GoodJob::Adapter::InlineBuffer.capture do
|
58
62
|
advisory_lock_maybe(lock) do
|
59
63
|
Batch.within_thread(batch_id: nil, batch_callback_id: id) do
|
60
64
|
reload
|
61
|
-
|
65
|
+
|
66
|
+
if job_discarded && !discarded_at
|
62
67
|
update(discarded_at: Time.current)
|
63
68
|
on_discard.constantize.set(priority: callback_priority, queue: callback_queue_name).perform_later(to_batch, { event: :discard }) if on_discard.present?
|
64
69
|
end
|
65
70
|
|
66
|
-
if enqueued_at && !finished_at && jobs.where(finished_at: nil).count.zero?
|
67
|
-
update(finished_at: Time.current)
|
71
|
+
if enqueued_at && !(self.class.jobs_finished_at_migrated? ? jobs_finished_at : finished_at) && jobs.where(finished_at: nil).count.zero?
|
72
|
+
self.class.jobs_finished_at_migrated? ? update(jobs_finished_at: Time.current) : update(finished_at: Time.current)
|
73
|
+
|
68
74
|
on_success.constantize.set(priority: callback_priority, queue: callback_queue_name).perform_later(to_batch, { event: :success }) if !discarded_at && on_success.present?
|
69
75
|
on_finish.constantize.set(priority: callback_priority, queue: callback_queue_name).perform_later(to_batch, { event: :finish }) if on_finish.present?
|
70
76
|
end
|
77
|
+
|
78
|
+
update(finished_at: Time.current) if !finished_at && self.class.jobs_finished_at_migrated? && jobs_finished? && callback_jobs.where(finished_at: nil).count.zero?
|
71
79
|
end
|
72
80
|
end
|
73
81
|
end
|
@@ -97,6 +105,14 @@ module GoodJob
|
|
97
105
|
self.serialized_properties = value
|
98
106
|
end
|
99
107
|
|
108
|
+
def jobs_finished?
|
109
|
+
self.class.jobs_finished_at_migrated? ? jobs_finished_at : finished_at
|
110
|
+
end
|
111
|
+
|
112
|
+
def jobs_finished_at
|
113
|
+
self.class.jobs_finished_at_migrated? ? self[:jobs_finished_at] : self[:finished_at]
|
114
|
+
end
|
115
|
+
|
100
116
|
private
|
101
117
|
|
102
118
|
def advisory_lock_maybe(value, &block)
|
data/app/models/good_job/job.rb
CHANGED
@@ -40,6 +40,7 @@ module GoodJob
|
|
40
40
|
set_callback :perform_unlocked, :after, :continue_discard_or_finish_batch
|
41
41
|
|
42
42
|
belongs_to :batch, class_name: 'GoodJob::BatchRecord', inverse_of: :jobs, optional: true
|
43
|
+
belongs_to :callback_batch, class_name: 'GoodJob::BatchRecord', foreign_key: :batch_callback_id, inverse_of: :callback_jobs, optional: true
|
43
44
|
belongs_to :locked_by_process, class_name: "GoodJob::Process", foreign_key: :locked_by_id, inverse_of: :locked_jobs, optional: true
|
44
45
|
has_many :executions, class_name: 'GoodJob::Execution', foreign_key: 'active_job_id', primary_key: "id", inverse_of: :job, dependent: :delete_all
|
45
46
|
|
@@ -743,6 +744,7 @@ module GoodJob
|
|
743
744
|
|
744
745
|
def continue_discard_or_finish_batch
|
745
746
|
batch._continue_discard_or_finish(self) if batch.present?
|
747
|
+
callback_batch._continue_discard_or_finish if callback_batch.present?
|
746
748
|
end
|
747
749
|
|
748
750
|
def active_job_data
|
data/config/routes.rb
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class AddJobsFinishedAtToGoodJobBatches < ActiveRecord::Migration<%= migration_version %>
|
4
|
+
def change
|
5
|
+
reversible do |dir|
|
6
|
+
dir.up do
|
7
|
+
# Ensure this incremental update migration is idempotent
|
8
|
+
# with monolithic install migration.
|
9
|
+
return if connection.column_exists?(:good_job_batches, :jobs_finished_at)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
change_table :good_job_batches do |t|
|
14
|
+
t.datetime :jobs_finished_at
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/good_job/adapter.rb
CHANGED
data/lib/good_job/version.rb
CHANGED
data/lib/good_job.rb
CHANGED
@@ -171,10 +171,10 @@ module GoodJob
|
|
171
171
|
_shutdown_all(Capsule.instances, :restart, timeout: timeout)
|
172
172
|
end
|
173
173
|
|
174
|
-
# Sends +#shutdown+ or +#restart+ to executable objects ({GoodJob::Notifier}, {GoodJob::Poller}, {GoodJob::Scheduler}, {GoodJob::MultiScheduler}, {GoodJob::CronManager})
|
174
|
+
# Sends +#shutdown+ or +#restart+ to executable objects ({GoodJob::Notifier}, {GoodJob::Poller}, {GoodJob::Scheduler}, {GoodJob::MultiScheduler}, {GoodJob::CronManager}, {GoodJob::SharedExecutor})
|
175
175
|
# @param executables [Array<Notifier, Poller, Scheduler, MultiScheduler, CronManager, SharedExecutor>] Objects to shut down.
|
176
|
-
# @param method_name [
|
177
|
-
# @param timeout [nil,Numeric]
|
176
|
+
# @param method_name [Symbol] Method to call, e.g. +:shutdown+ or +:restart+.
|
177
|
+
# @param timeout [nil, Numeric] Seconds to wait for actively executing jobs to finish.
|
178
178
|
# @param after [Array<Notifier, Poller, Scheduler, MultiScheduler, CronManager, SharedExecutor>] Objects to shut down after initial executables shut down.
|
179
179
|
# @return [void]
|
180
180
|
def self._shutdown_all(executables, method_name = :shutdown, timeout: -1, after: [])
|
@@ -290,7 +290,7 @@ module GoodJob
|
|
290
290
|
# For use in tests/CI to validate GoodJob is up-to-date.
|
291
291
|
# @return [Boolean]
|
292
292
|
def self.migrated?
|
293
|
-
|
293
|
+
GoodJob::BatchRecord.jobs_finished_at_migrated?
|
294
294
|
end
|
295
295
|
end
|
296
296
|
|
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.3.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-09-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|
@@ -340,6 +340,7 @@ files:
|
|
340
340
|
- lib/generators/good_job/install_generator.rb
|
341
341
|
- lib/generators/good_job/templates/install/migrations/create_good_jobs.rb.erb
|
342
342
|
- lib/generators/good_job/templates/update/migrations/01_create_good_jobs.rb.erb
|
343
|
+
- lib/generators/good_job/templates/update/migrations/02_add_jobs_finished_at_to_good_job_batches.rb.erb
|
343
344
|
- lib/generators/good_job/update_generator.rb
|
344
345
|
- lib/good_job.rb
|
345
346
|
- lib/good_job/active_job_extensions/batches.rb
|