good_job 4.13.1 → 4.13.2
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 +20 -0
- data/app/models/good_job/batch.rb +6 -2
- data/app/models/good_job/batch_record.rb +33 -11
- data/app/models/good_job/job.rb +59 -27
- data/app/views/layouts/good_job/application.html.erb +2 -0
- data/lib/good_job/version.rb +1 -1
- data/lib/good_job.rb +4 -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: 3274686b09e03b2ec9b5d58f3b8bf70472e30c739b907697e7ad1f2ad7ce6b50
|
|
4
|
+
data.tar.gz: 0f2ee28df948382eb23cffd0535545462490737c62c3d9133be5afb7ef3cfc52
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bea1412da3fc1d276688733cd2d5aa622939211b8cc4cbdaa52a0bc5543ded93f5350be14d0cdbed987b988cc9b205dd0dc144b209d7ecc5ced25dad26221ec7
|
|
7
|
+
data.tar.gz: 61240a584b06c7871f815d123a78a9c3066a8a739a49f2a9f403bdfcf255f97e691ad5fd5754a301f7b7e5c66a3cb09161d312348c68a022a958d5e5cbba27e1
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [v4.13.2](https://github.com/bensheldon/good_job/tree/v4.13.2) (2026-01-29)
|
|
4
|
+
|
|
5
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v4.13.1...v4.13.2)
|
|
6
|
+
|
|
7
|
+
**Fixed bugs:**
|
|
8
|
+
|
|
9
|
+
- Check for graceful shutdown inside job cleanup loops [\#1711](https://github.com/bensheldon/good_job/pull/1711) ([bdewater-thatch](https://github.com/bdewater-thatch))
|
|
10
|
+
- Add title to Good Job Dashboard layout [\#1701](https://github.com/bensheldon/good_job/pull/1701) ([mockdeep](https://github.com/mockdeep))
|
|
11
|
+
|
|
12
|
+
**Closed issues:**
|
|
13
|
+
|
|
14
|
+
- Test failures against rails-head [\#1704](https://github.com/bensheldon/good_job/issues/1704)
|
|
15
|
+
|
|
16
|
+
**Merged pull requests:**
|
|
17
|
+
|
|
18
|
+
- Add test for Migration generator with custom migration path [\#1709](https://github.com/bensheldon/good_job/pull/1709) ([bensheldon](https://github.com/bensheldon))
|
|
19
|
+
- Support Rails 8.2-dev `enqueue\_after\_transaction\_commit by deferring framework enqueuing preemptively [\#1707](https://github.com/bensheldon/good_job/pull/1707) ([bensheldon](https://github.com/bensheldon))
|
|
20
|
+
- Add Ruby 4.0 to CI [\#1705](https://github.com/bensheldon/good_job/pull/1705) ([Earlopain](https://github.com/Earlopain))
|
|
21
|
+
- Bump actions/upload-artifact from 5 to 6 [\#1703](https://github.com/bensheldon/good_job/pull/1703) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
22
|
+
|
|
3
23
|
## [v4.13.1](https://github.com/bensheldon/good_job/tree/v4.13.1) (2025-12-16)
|
|
4
24
|
|
|
5
25
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v4.13.0...v4.13.1)
|
|
@@ -151,8 +151,12 @@ module GoodJob
|
|
|
151
151
|
update_attributes = { discarded_at: nil, finished_at: nil }
|
|
152
152
|
update_attributes[:jobs_finished_at] = nil if GoodJob::BatchRecord.jobs_finished_at_migrated?
|
|
153
153
|
record.update!(update_attributes)
|
|
154
|
-
|
|
155
|
-
record.
|
|
154
|
+
|
|
155
|
+
discarded_jobs = record.jobs.discarded
|
|
156
|
+
Job.defer_after_commit_maybe(discarded_jobs) do
|
|
157
|
+
discarded_jobs.each(&:retry_job)
|
|
158
|
+
record._continue_discard_or_finish(lock: false)
|
|
159
|
+
end
|
|
156
160
|
end
|
|
157
161
|
end
|
|
158
162
|
end
|
|
@@ -59,25 +59,47 @@ module GoodJob
|
|
|
59
59
|
job_discarded = job && job.finished_at.present? && job.error.present?
|
|
60
60
|
buffer = GoodJob::Adapter::InlineBuffer.capture do
|
|
61
61
|
advisory_lock_maybe(lock) do
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
reload
|
|
63
|
+
|
|
64
|
+
if job_discarded && !discarded_at
|
|
65
|
+
update(discarded_at: Time.current)
|
|
66
|
+
|
|
67
|
+
if on_discard.present?
|
|
68
|
+
discard_job_class = on_discard.constantize
|
|
69
|
+
Job.defer_after_commit_maybe(discard_job_class) do
|
|
70
|
+
Batch.within_thread(batch_id: nil, batch_callback_id: id) do
|
|
71
|
+
discard_job_class.set(priority: callback_priority, queue: callback_queue_name).perform_later(to_batch, { event: :discard })
|
|
72
|
+
end
|
|
73
|
+
end
|
|
68
74
|
end
|
|
75
|
+
end
|
|
69
76
|
|
|
70
|
-
|
|
71
|
-
|
|
77
|
+
if enqueued_at && !(self.class.jobs_finished_at_migrated? ? jobs_finished_at : finished_at) && jobs.where(finished_at: nil).none?
|
|
78
|
+
self.class.jobs_finished_at_migrated? ? update(jobs_finished_at: Time.current) : update(finished_at: Time.current)
|
|
72
79
|
|
|
73
|
-
|
|
74
|
-
|
|
80
|
+
if !discarded_at && on_success.present?
|
|
81
|
+
success_job_class = on_success.constantize
|
|
82
|
+
Job.defer_after_commit_maybe(success_job_class) do
|
|
83
|
+
Batch.within_thread(batch_id: nil, batch_callback_id: id) do
|
|
84
|
+
success_job_class.set(priority: callback_priority, queue: callback_queue_name).perform_later(to_batch, { event: :success })
|
|
85
|
+
end
|
|
86
|
+
end
|
|
75
87
|
end
|
|
76
88
|
|
|
77
|
-
|
|
89
|
+
if on_finish.present?
|
|
90
|
+
finish_job_class = on_finish.constantize
|
|
91
|
+
Job.defer_after_commit_maybe(finish_job_class) do
|
|
92
|
+
Batch.within_thread(batch_id: nil, batch_callback_id: id) do
|
|
93
|
+
on_finish.constantize.set(priority: callback_priority, queue: callback_queue_name).perform_later(to_batch, { event: :finish })
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
78
97
|
end
|
|
98
|
+
|
|
99
|
+
update(finished_at: Time.current) if !finished_at && self.class.jobs_finished_at_migrated? && jobs_finished? && callback_jobs.where(finished_at: nil).none?
|
|
79
100
|
end
|
|
80
101
|
end
|
|
102
|
+
|
|
81
103
|
buffer.call
|
|
82
104
|
end
|
|
83
105
|
|
data/app/models/good_job/job.rb
CHANGED
|
@@ -420,6 +420,33 @@ module GoodJob
|
|
|
420
420
|
[error.class.to_s, ERROR_MESSAGE_SEPARATOR, error.message].join
|
|
421
421
|
end
|
|
422
422
|
|
|
423
|
+
# When code needs to optionally handle enqueue_after_transaction_commit
|
|
424
|
+
def self.defer_after_commit_maybe(good_job_or_active_job_classes)
|
|
425
|
+
if enqueue_after_commit?(good_job_or_active_job_classes)
|
|
426
|
+
ActiveRecord.after_all_transactions_commit { yield(true) }
|
|
427
|
+
else
|
|
428
|
+
yield(false)
|
|
429
|
+
end
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
def self.enqueue_after_commit?(good_job_or_active_job_classes)
|
|
433
|
+
good_job_or_active_job_classes = Array(good_job_or_active_job_classes)
|
|
434
|
+
|
|
435
|
+
feature_exists = ActiveRecord.respond_to?(:after_all_transactions_commit)
|
|
436
|
+
feature_exists && good_job_or_active_job_classes.any? do |klass|
|
|
437
|
+
active_job_class = case klass
|
|
438
|
+
when String
|
|
439
|
+
klass.constantize
|
|
440
|
+
when Job
|
|
441
|
+
klass.job_class.constantize
|
|
442
|
+
else
|
|
443
|
+
klass
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
active_job_class.respond_to?(:enqueue_after_transaction_commit)
|
|
447
|
+
end
|
|
448
|
+
end
|
|
449
|
+
|
|
423
450
|
# TODO: it would be nice to enforce these values at the model
|
|
424
451
|
# validates :active_job_id, presence: true
|
|
425
452
|
# validates :scheduled_at, presence: true
|
|
@@ -499,41 +526,46 @@ module GoodJob
|
|
|
499
526
|
# This action will create a new {Execution} record for the job.
|
|
500
527
|
# @return [ActiveJob::Base]
|
|
501
528
|
def retry_job
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
529
|
+
Rails.application.executor.wrap do
|
|
530
|
+
with_advisory_lock do
|
|
531
|
+
reload
|
|
532
|
+
active_job = self.active_job(ignore_deserialization_errors: true)
|
|
533
|
+
|
|
534
|
+
raise ActiveJobDeserializationError if active_job.nil?
|
|
535
|
+
raise AdapterNotGoodJobError unless active_job.class.queue_adapter.is_a? GoodJob::Adapter
|
|
536
|
+
raise ActionForStateMismatchError if finished_at.blank? || error.blank?
|
|
537
|
+
|
|
538
|
+
# Update the executions count because the previous execution will not have been preserved
|
|
539
|
+
# Do not update `exception_executions` because that comes from rescue_from's arguments
|
|
540
|
+
active_job.executions = (active_job.executions || 0) + 1
|
|
541
|
+
|
|
542
|
+
begin
|
|
543
|
+
error_class, error_message = error.split(ERROR_MESSAGE_SEPARATOR).map(&:strip)
|
|
544
|
+
error = error_class.constantize.new(error_message)
|
|
545
|
+
rescue StandardError
|
|
546
|
+
error = StandardError.new(error)
|
|
547
|
+
end
|
|
520
548
|
|
|
521
|
-
|
|
522
|
-
GoodJob::CurrentThread.within do |current_thread|
|
|
523
|
-
current_thread.job = self
|
|
524
|
-
current_thread.retry_now = true
|
|
549
|
+
new_active_job = nil
|
|
525
550
|
|
|
526
551
|
transaction do
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
552
|
+
Job.defer_after_commit_maybe(active_job.class) do
|
|
553
|
+
GoodJob::CurrentThread.within do |current_thread|
|
|
554
|
+
current_thread.job = self
|
|
555
|
+
current_thread.retry_now = true
|
|
556
|
+
|
|
557
|
+
# NOTE: I18n.with_locale necessary until fixed in rails https://github.com/rails/rails/pull/52121
|
|
558
|
+
I18n.with_locale(active_job.locale) do
|
|
559
|
+
new_active_job = active_job.retry_job(wait: 0, error: error)
|
|
560
|
+
end
|
|
561
|
+
end
|
|
530
562
|
end
|
|
531
563
|
self.error_event = :retried if error
|
|
532
564
|
save!
|
|
533
565
|
end
|
|
534
|
-
end
|
|
535
566
|
|
|
536
|
-
|
|
567
|
+
new_active_job
|
|
568
|
+
end
|
|
537
569
|
end
|
|
538
570
|
end
|
|
539
571
|
|
|
@@ -32,6 +32,8 @@
|
|
|
32
32
|
|
|
33
33
|
<%= tag.script "import \"application\";".html_safe, type: "module", nonce: content_security_policy_nonce %>
|
|
34
34
|
|
|
35
|
+
<title>Good Job Dashboard</title>
|
|
36
|
+
<%= tag.link rel: "icon", href: 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="10 0 100 100"><text y=".90em" font-size="90">👍</text></svg>' %>
|
|
35
37
|
<%= csrf_meta_tags %>
|
|
36
38
|
<%= csp_meta_tag %>
|
|
37
39
|
|
data/lib/good_job/version.rb
CHANGED
data/lib/good_job.rb
CHANGED
|
@@ -217,6 +217,8 @@ module GoodJob
|
|
|
217
217
|
jobs_query = GoodJob::Job.finished_before(timestamp).order(finished_at: :asc).limit(in_batches_of)
|
|
218
218
|
jobs_query = jobs_query.succeeded unless include_discarded
|
|
219
219
|
loop do
|
|
220
|
+
break if GoodJob.current_thread_shutting_down?
|
|
221
|
+
|
|
220
222
|
active_job_ids = jobs_query.pluck(:active_job_id)
|
|
221
223
|
break if active_job_ids.empty?
|
|
222
224
|
|
|
@@ -230,6 +232,8 @@ module GoodJob
|
|
|
230
232
|
batches_query = GoodJob::BatchRecord.finished_before(timestamp).limit(in_batches_of)
|
|
231
233
|
batches_query = batches_query.succeeded unless include_discarded
|
|
232
234
|
loop do
|
|
235
|
+
break if GoodJob.current_thread_shutting_down?
|
|
236
|
+
|
|
233
237
|
deleted = batches_query.delete_all
|
|
234
238
|
break if deleted.zero?
|
|
235
239
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: good_job
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.13.
|
|
4
|
+
version: 4.13.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ben Sheldon
|
|
@@ -426,7 +426,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
426
426
|
- !ruby/object:Gem::Version
|
|
427
427
|
version: '0'
|
|
428
428
|
requirements: []
|
|
429
|
-
rubygems_version:
|
|
429
|
+
rubygems_version: 4.0.2
|
|
430
430
|
specification_version: 4
|
|
431
431
|
summary: A multithreaded, Postgres-based ActiveJob backend for Ruby on Rails
|
|
432
432
|
test_files: []
|