good_job 3.11.1 → 3.12.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 +8 -0
- data/README.md +18 -0
- data/app/models/good_job/execution.rb +20 -25
- data/lib/good_job/active_job_extensions/interrupt_errors.rb +16 -0
- data/lib/good_job/current_thread.rb +7 -0
- data/lib/good_job/interrupt_error.rb +6 -0
- data/lib/good_job/version.rb +1 -1
- data/lib/good_job.rb +2 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eeb15f65ff801785a0df591dec95a0e044a4f5d7e61e6b2483003c4b2afd8cb3
|
4
|
+
data.tar.gz: e5c631765c1303d1fee0597313bbcb5d3844b85ad49600f2609c83149885872d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf0ed8436074ca82d718b64a76b4b1ce36f4bc2a085fe765b04eb101ae7886d0823bb50faa7816fd3a0dcb56d308dc568a7cdd86373d0afcb49bc2d22c045105
|
7
|
+
data.tar.gz: 8bd8e67ebfcb2b90a7e1ce6a542cf659e8d4cd37f31782a3a3cd5d26cfedba1e85e9a57835a8a9e78cd731f304b055c21802ca1c68fc2fcffb32ec9b3050ebdf
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v3.12.0](https://github.com/bensheldon/good_job/tree/v3.12.0) (2023-02-07)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.11.1...v3.12.0)
|
6
|
+
|
7
|
+
**Merged pull requests:**
|
8
|
+
|
9
|
+
- Create `InterruptErrors` extension to raise an exception when an interrupted job is retried [\#830](https://github.com/bensheldon/good_job/pull/830) ([bensheldon](https://github.com/bensheldon))
|
10
|
+
|
3
11
|
## [v3.11.1](https://github.com/bensheldon/good_job/tree/v3.11.1) (2023-02-06)
|
4
12
|
|
5
13
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.11.0...v3.11.1)
|
data/README.md
CHANGED
@@ -55,6 +55,7 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
|
|
55
55
|
- [Exceptions](#exceptions)
|
56
56
|
- [Retries](#retries)
|
57
57
|
- [ActionMailer retries](#actionmailer-retries)
|
58
|
+
- [Interrupts](#interrupts)
|
58
59
|
- [Timeouts](#timeouts)
|
59
60
|
- [Optimize queues, threads, and processes](#optimize-queues-threads-and-processes)
|
60
61
|
- [Database connections](#database-connections)
|
@@ -829,6 +830,23 @@ end
|
|
829
830
|
Note, that `ActionMailer::MailDeliveryJob` is a default since Rails 6.0. Be sure that your app is using that class, as it
|
830
831
|
might also be configured to use (deprecated now) `ActionMailer::DeliveryJob`.
|
831
832
|
|
833
|
+
### Interrupts
|
834
|
+
|
835
|
+
Jobs will be automatically retried if the process is interrupted while performing a job, for example as the result of a `SIGKILL` or power failure.
|
836
|
+
|
837
|
+
If you need more control over interrupt-caused retries, include the `GoodJob::ActiveJobExtensions::InterruptErrors` extension in your job closs. When an interrupted job is retried, the extension will raise a `GoodJob::InterruptError` exception within the job, which allows you to use ActiveJob's `retry_on` and `discard_on` to control the behavior of the job.
|
838
|
+
|
839
|
+
```ruby
|
840
|
+
class MyJob < ApplicationJob
|
841
|
+
# The extension must be included before other extensions
|
842
|
+
include GoodJob::ActiveJobExtensions::InterruptErrors
|
843
|
+
# Discard the job if it is interrupted
|
844
|
+
discard_on InterruptError
|
845
|
+
# Retry the job if it is interrupted
|
846
|
+
retry_on InterruptError, wait: 0, attempts: Float::INFINITY
|
847
|
+
end
|
848
|
+
```
|
849
|
+
|
832
850
|
### Timeouts
|
833
851
|
|
834
852
|
Job timeouts can be configured with an `around_perform`:
|
@@ -315,10 +315,27 @@ module GoodJob
|
|
315
315
|
run_callbacks(:perform) do
|
316
316
|
raise PreviouslyPerformedError, 'Cannot perform a job that has already been performed' if finished_at
|
317
317
|
|
318
|
-
|
319
|
-
|
318
|
+
result = GoodJob::CurrentThread.within do |current_thread|
|
319
|
+
current_thread.reset
|
320
|
+
current_thread.execution = self
|
320
321
|
|
321
|
-
|
322
|
+
current_thread.execution_interrupted = performed_at if performed_at
|
323
|
+
update!(performed_at: Time.current)
|
324
|
+
|
325
|
+
ActiveSupport::Notifications.instrument("perform_job.good_job", { execution: self, process_id: current_thread.process_id, thread_name: current_thread.thread_name }) do
|
326
|
+
value = ActiveJob::Base.execute(active_job_data)
|
327
|
+
|
328
|
+
if value.is_a?(Exception)
|
329
|
+
handled_error = value
|
330
|
+
value = nil
|
331
|
+
end
|
332
|
+
handled_error ||= current_thread.error_on_retry || current_thread.error_on_discard
|
333
|
+
|
334
|
+
ExecutionResult.new(value: value, handled_error: handled_error, retried: current_thread.error_on_retry.present?)
|
335
|
+
rescue StandardError => e
|
336
|
+
ExecutionResult.new(value: nil, unhandled_error: e)
|
337
|
+
end
|
338
|
+
end
|
322
339
|
|
323
340
|
job_error = result.handled_error || result.unhandled_error
|
324
341
|
self.error = [job_error.class, ERROR_MESSAGE_SEPARATOR, job_error.message].join if job_error
|
@@ -408,28 +425,6 @@ module GoodJob
|
|
408
425
|
end
|
409
426
|
end
|
410
427
|
|
411
|
-
# @return [ExecutionResult]
|
412
|
-
def execute
|
413
|
-
GoodJob::CurrentThread.within do |current_thread|
|
414
|
-
current_thread.reset
|
415
|
-
current_thread.execution = self
|
416
|
-
|
417
|
-
ActiveSupport::Notifications.instrument("perform_job.good_job", { execution: self, process_id: current_thread.process_id, thread_name: current_thread.thread_name }) do
|
418
|
-
value = ActiveJob::Base.execute(active_job_data)
|
419
|
-
|
420
|
-
if value.is_a?(Exception)
|
421
|
-
handled_error = value
|
422
|
-
value = nil
|
423
|
-
end
|
424
|
-
handled_error ||= current_thread.error_on_retry || current_thread.error_on_discard
|
425
|
-
|
426
|
-
ExecutionResult.new(value: value, handled_error: handled_error, retried: current_thread.error_on_retry.present?)
|
427
|
-
rescue StandardError => e
|
428
|
-
ExecutionResult.new(value: nil, unhandled_error: e)
|
429
|
-
end
|
430
|
-
end
|
431
|
-
end
|
432
|
-
|
433
428
|
def reset_batch_values(&block)
|
434
429
|
GoodJob::Batch.within_thread(batch_id: nil, batch_callback_id: nil, &block)
|
435
430
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GoodJob
|
3
|
+
module ActiveJobExtensions
|
4
|
+
module InterruptErrors
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
around_perform do |_job, block|
|
9
|
+
raise InterruptError, "Interrupted after starting perform at '#{CurrentThread.execution_interrupted}'" if CurrentThread.execution_interrupted.present?
|
10
|
+
|
11
|
+
block.call
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -12,6 +12,7 @@ module GoodJob
|
|
12
12
|
error_on_discard
|
13
13
|
error_on_retry
|
14
14
|
execution
|
15
|
+
execution_interrupted
|
15
16
|
].freeze
|
16
17
|
|
17
18
|
# @!attribute [rw] cron_at
|
@@ -44,6 +45,12 @@ module GoodJob
|
|
44
45
|
# @return [GoodJob::Execution, nil]
|
45
46
|
thread_mattr_accessor :execution
|
46
47
|
|
48
|
+
# @!attribute [rw] execution_interrupted
|
49
|
+
# @!scope class
|
50
|
+
# Execution Interrupted
|
51
|
+
# @return [Boolean, nil]
|
52
|
+
thread_mattr_accessor :execution_interrupted
|
53
|
+
|
47
54
|
# Resets attributes
|
48
55
|
# @param [Hash] values to assign
|
49
56
|
# @return [void]
|
data/lib/good_job/version.rb
CHANGED
data/lib/good_job.rb
CHANGED
@@ -9,6 +9,8 @@ require "good_job/adapter"
|
|
9
9
|
require "active_job/queue_adapters/good_job_adapter"
|
10
10
|
require "good_job/active_job_extensions/batches"
|
11
11
|
require "good_job/active_job_extensions/concurrency"
|
12
|
+
require "good_job/interrupt_error"
|
13
|
+
require "good_job/active_job_extensions/interrupt_errors"
|
12
14
|
require "good_job/active_job_extensions/notify_options"
|
13
15
|
|
14
16
|
require "good_job/assignable_connection"
|
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.12.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: 2023-02-
|
11
|
+
date: 2023-02-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|
@@ -403,6 +403,7 @@ files:
|
|
403
403
|
- lib/good_job.rb
|
404
404
|
- lib/good_job/active_job_extensions/batches.rb
|
405
405
|
- lib/good_job/active_job_extensions/concurrency.rb
|
406
|
+
- lib/good_job/active_job_extensions/interrupt_errors.rb
|
406
407
|
- lib/good_job/active_job_extensions/notify_options.rb
|
407
408
|
- lib/good_job/adapter.rb
|
408
409
|
- lib/good_job/assignable_connection.rb
|
@@ -415,6 +416,7 @@ files:
|
|
415
416
|
- lib/good_job/daemon.rb
|
416
417
|
- lib/good_job/dependencies.rb
|
417
418
|
- lib/good_job/engine.rb
|
419
|
+
- lib/good_job/interrupt_error.rb
|
418
420
|
- lib/good_job/job_performer.rb
|
419
421
|
- lib/good_job/log_subscriber.rb
|
420
422
|
- lib/good_job/multi_scheduler.rb
|