activejob 6.1.4 → 7.0.0.rc1
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 +45 -132
- data/MIT-LICENSE +1 -1
- data/README.md +3 -3
- data/lib/active_job/arguments.rb +10 -15
- data/lib/active_job/base.rb +2 -2
- data/lib/active_job/callbacks.rb +3 -28
- data/lib/active_job/configured_job.rb +5 -7
- data/lib/active_job/core.rb +21 -1
- data/lib/active_job/enqueuing.rb +23 -13
- data/lib/active_job/exceptions.rb +4 -2
- data/lib/active_job/execution.rb +13 -8
- data/lib/active_job/gem_version.rb +4 -4
- data/lib/active_job/instrumentation.rb +9 -5
- data/lib/active_job/log_subscriber.rb +1 -1
- data/lib/active_job/logging.rb +8 -5
- data/lib/active_job/queue_adapter.rb +1 -1
- data/lib/active_job/queue_adapters/async_adapter.rb +6 -6
- data/lib/active_job/queue_adapters/backburner_adapter.rb +3 -3
- data/lib/active_job/queue_adapters/delayed_job_adapter.rb +14 -4
- data/lib/active_job/queue_adapters/inline_adapter.rb +2 -2
- data/lib/active_job/queue_adapters/que_adapter.rb +3 -3
- data/lib/active_job/queue_adapters/queue_classic_adapter.rb +3 -3
- data/lib/active_job/queue_adapters/resque_adapter.rb +3 -3
- data/lib/active_job/queue_adapters/sidekiq_adapter.rb +3 -3
- data/lib/active_job/queue_adapters/sneakers_adapter.rb +3 -3
- data/lib/active_job/queue_adapters/sucker_punch_adapter.rb +3 -3
- data/lib/active_job/queue_adapters/test_adapter.rb +3 -2
- data/lib/active_job/queue_name.rb +1 -1
- data/lib/active_job/railtie.rb +22 -1
- data/lib/active_job/serializers/module_serializer.rb +1 -0
- data/lib/active_job/serializers/range_serializer.rb +23 -0
- data/lib/active_job/serializers.rb +3 -1
- data/lib/active_job/test_helper.rb +37 -13
- data/lib/active_job/timezones.rb +1 -1
- data/lib/active_job/translation.rb +1 -1
- data/lib/active_job.rb +2 -1
- metadata +13 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4ae9afbd809eb16b45a08dd01c5a4b380bc0ce41055e074c0156ca1f0fae2650
|
4
|
+
data.tar.gz: 87653df366fcb02cead16d16a256fb99292cdce5f5a5504ceb2efe205378ca4a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 07b924bedc982b2c43b7f0a75bdb3a9f0770730a17cb4c26a1dd553923ac2bcf5f9b186279e0d11d36975d3d128df27caaa1e3ca8d225a472c70b7fccbbfd219
|
7
|
+
data.tar.gz: 3bff03b822d41e5a88bf1e73273e09fa06f2ac311e508d1c99bfb72d852980beffed30e24b0cfdd1fa8fce9a05dd04b0ef108fb9ef9c66fe67fbfe0dda206475
|
data/CHANGELOG.md
CHANGED
@@ -1,171 +1,84 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
* No changes.
|
4
|
-
|
5
|
-
|
6
|
-
## Rails 6.1.3.2 (May 05, 2021) ##
|
7
|
-
|
8
|
-
* No changes.
|
9
|
-
|
10
|
-
|
11
|
-
## Rails 6.1.3.1 (March 26, 2021) ##
|
12
|
-
|
13
|
-
* No changes.
|
14
|
-
|
15
|
-
|
16
|
-
## Rails 6.1.3 (February 17, 2021) ##
|
17
|
-
|
18
|
-
* No changes.
|
19
|
-
|
20
|
-
|
21
|
-
## Rails 6.1.2.1 (February 10, 2021) ##
|
22
|
-
|
23
|
-
* No changes.
|
24
|
-
|
25
|
-
|
26
|
-
## Rails 6.1.2 (February 09, 2021) ##
|
27
|
-
|
28
|
-
* No changes.
|
29
|
-
|
30
|
-
|
31
|
-
## Rails 6.1.1 (January 07, 2021) ##
|
32
|
-
|
33
|
-
* Make `retry_job` return the job that was created.
|
1
|
+
* Remove deprecated `:return_false_on_aborted_enqueue` option.
|
34
2
|
|
35
3
|
*Rafael Mendonça França*
|
36
4
|
|
37
|
-
*
|
38
|
-
|
39
|
-
*Mikkel Malmberg*
|
40
|
-
|
41
|
-
|
42
|
-
## Rails 6.1.0 (December 09, 2020) ##
|
43
|
-
|
44
|
-
* Recover nano precision when serializing `Time`, `TimeWithZone` and `DateTime` objects.
|
45
|
-
|
46
|
-
*Alan Tan*
|
47
|
-
|
48
|
-
* Deprecate `config.active_job.return_false_on_aborted_enqueue`.
|
5
|
+
* Deprecated `Rails.config.active_job.skip_after_callbacks_if_terminated`.
|
49
6
|
|
50
7
|
*Rafael Mendonça França*
|
51
8
|
|
52
|
-
*
|
9
|
+
* Removed deprecated behavior that was not halting `after_enqueue`/`after_perform` callbacks when a
|
10
|
+
previous callback was halted with `throw :abort`.
|
53
11
|
|
54
12
|
*Rafael Mendonça França*
|
55
13
|
|
56
|
-
*
|
57
|
-
|
14
|
+
* Raise an `SerializationError` in `Serializer::ModuleSerializer`
|
15
|
+
if the module name is not present.
|
58
16
|
|
59
|
-
*
|
17
|
+
*Veerpal Brar*
|
60
18
|
|
61
|
-
* `ActiveJob::TestCase#perform_enqueued_jobs` without a block removes performed jobs from the queue.
|
62
19
|
|
63
|
-
|
20
|
+
## Rails 7.0.0.alpha2 (September 15, 2021) ##
|
64
21
|
|
65
|
-
|
66
|
-
def test_jobs
|
67
|
-
HelloJob.perform_later("rafael")
|
68
|
-
perform_enqueued_jobs # only runs with "rafael"
|
69
|
-
HelloJob.perform_later("david")
|
70
|
-
perform_enqueued_jobs # only runs with "david"
|
71
|
-
end
|
72
|
-
```
|
73
|
-
|
74
|
-
*Étienne Barrié*
|
75
|
-
|
76
|
-
* `ActiveJob::TestCase#perform_enqueued_jobs` will no longer perform retries:
|
77
|
-
|
78
|
-
When calling `perform_enqueued_jobs` without a block, the adapter will
|
79
|
-
now perform jobs that are **already** in the queue. Jobs that will end up in
|
80
|
-
the queue afterwards won't be performed.
|
22
|
+
* No changes.
|
81
23
|
|
82
|
-
This change only affects `perform_enqueued_jobs` when no block is given.
|
83
24
|
|
84
|
-
|
25
|
+
## Rails 7.0.0.alpha1 (September 15, 2021) ##
|
85
26
|
|
86
|
-
*
|
27
|
+
* Allow a job to retry indefinitely
|
87
28
|
|
88
|
-
|
29
|
+
The `attempts` parameter of the `retry_on` method now accepts the
|
30
|
+
symbol reference `:unlimited` in addition to a specific number of retry
|
31
|
+
attempts to allow a developer to specify that a job should retry
|
32
|
+
forever until it succeeds.
|
89
33
|
|
90
|
-
|
34
|
+
class MyJob < ActiveJob::Base
|
35
|
+
retry_on(AlwaysRetryException, attempts: :unlimited)
|
91
36
|
|
92
|
-
|
93
|
-
before_enqueue { throw(:abort) }
|
94
|
-
after_enqueue { # won't enter here anymore }
|
37
|
+
# the actual job code
|
95
38
|
end
|
96
39
|
|
97
|
-
|
98
|
-
This behaviour is a breaking change and won't take effect until Rails 6.2.
|
99
|
-
To enable this behaviour in your app right now, you can add in your app's configuration file
|
100
|
-
`config.active_job.skip_after_callbacks_if_terminated = true`.
|
101
|
-
|
102
|
-
*Edouard Chin*
|
40
|
+
*Daniel Morton*
|
103
41
|
|
104
|
-
*
|
42
|
+
* Added possibility to check on `:priority` in test helper methods
|
43
|
+
`assert_enqueued_with` and `assert_performed_with`.
|
105
44
|
|
106
|
-
|
45
|
+
*Wojciech Wnętrzak*
|
107
46
|
|
108
|
-
|
109
|
-
class MyJob < ApplicationJob
|
110
|
-
before_enqueue { throw(:abort) }
|
111
|
-
end
|
47
|
+
* OpenSSL constants are now used for Digest computations.
|
112
48
|
|
113
|
-
|
114
|
-
```
|
49
|
+
*Dirkjan Bussink*
|
115
50
|
|
116
|
-
|
117
|
-
because an exception happened during enqueuing. (i.e. Redis is down when you try to enqueue your job)
|
51
|
+
* Add a Serializer for the Range class.
|
118
52
|
|
119
|
-
|
53
|
+
This should allow things like `MyJob.perform_later(range: 1..100)`.
|
120
54
|
|
121
|
-
*
|
55
|
+
* Communicate enqueue failures to callers of `perform_later`.
|
122
56
|
|
123
|
-
|
124
|
-
|
57
|
+
`perform_later` can now optionally take a block which will execute after
|
58
|
+
the adapter attempts to enqueue the job. The block will receive the job
|
59
|
+
instance as an argument even if the enqueue was not successful.
|
60
|
+
Additionally, `ActiveJob` adapters now have the ability to raise an
|
61
|
+
`ActiveJob::EnqueueError` which will be caught and stored in the job
|
62
|
+
instance so code attempting to enqueue jobs can inspect any raised
|
63
|
+
`EnqueueError` using the block.
|
125
64
|
|
126
|
-
|
65
|
+
MyJob.perform_later do |job|
|
66
|
+
unless job.successfully_enqueued?
|
67
|
+
if job.enqueue_error&.message == "Redis was unavailable"
|
68
|
+
# invoke some code that will retry the job after a delay
|
69
|
+
end
|
127
70
|
end
|
128
71
|
end
|
129
72
|
|
130
|
-
|
131
|
-
to not put the sensitive argument in the logs.
|
132
|
-
|
133
|
-
*Rafael Mendonça França*
|
134
|
-
|
135
|
-
* Changes in `queue_name_prefix` of a job no longer affects all other jobs.
|
136
|
-
|
137
|
-
Fixes #37084.
|
138
|
-
|
139
|
-
*Lucas Mansur*
|
140
|
-
|
141
|
-
* Allow `Class` and `Module` instances to be serialized.
|
142
|
-
|
143
|
-
*Kevin Deisz*
|
144
|
-
|
145
|
-
* Log potential matches in `assert_enqueued_with` and `assert_performed_with`.
|
146
|
-
|
147
|
-
*Gareth du Plooy*
|
148
|
-
|
149
|
-
* Add `at` argument to the `perform_enqueued_jobs` test helper.
|
150
|
-
|
151
|
-
*John Crepezzi*, *Eileen Uchitelle*
|
152
|
-
|
153
|
-
* `assert_enqueued_with` and `assert_performed_with` can now test jobs with relative delay.
|
154
|
-
|
155
|
-
*Vlado Cingel*
|
73
|
+
*Daniel Morton*
|
156
74
|
|
157
|
-
*
|
75
|
+
* Don't log rescuable exceptions defined with `rescue_from`.
|
158
76
|
|
159
|
-
|
160
|
-
prevent the [thundering herd effect](https://en.wikipedia.org/wiki/Thundering_herd_problem). Defaults to
|
161
|
-
15% (represented as 0.15) but overridable via the `:jitter` option when using `retry_on`.
|
162
|
-
Jitter is applied when an `Integer`, `ActiveSupport::Duration` or `:exponentially_longer`, is passed to the `wait` argument in `retry_on`.
|
77
|
+
*Hu Hailin*
|
163
78
|
|
164
|
-
|
165
|
-
retry_on(MyError, wait: :exponentially_longer, jitter: 0.30)
|
166
|
-
```
|
79
|
+
* Allow `rescue_from` to rescue all exceptions.
|
167
80
|
|
168
|
-
*
|
81
|
+
*Adrianna Chang*, *Étienne Barrié*
|
169
82
|
|
170
83
|
|
171
|
-
Please check [6-
|
84
|
+
Please check [6-1-stable](https://github.com/rails/rails/blob/6-1-stable/activejob/CHANGELOG.md) for previous changes.
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -2,13 +2,13 @@
|
|
2
2
|
|
3
3
|
Active Job is a framework for declaring jobs and making them run on a variety
|
4
4
|
of queuing backends. These jobs can be everything from regularly scheduled
|
5
|
-
clean-ups, to billing charges, to mailings
|
6
|
-
small units of work and run in parallel
|
5
|
+
clean-ups, to billing charges, to mailings — anything that can be chopped up into
|
6
|
+
small units of work and run in parallel.
|
7
7
|
|
8
8
|
It also serves as the backend for Action Mailer's #deliver_later functionality
|
9
9
|
that makes it easy to turn any mailing into a job for running later. That's
|
10
10
|
one of the most common jobs in a modern web application: sending emails outside
|
11
|
-
|
11
|
+
the request-response cycle, so the user doesn't have to wait on it.
|
12
12
|
|
13
13
|
The main point is to ensure that all Rails apps will have a job infrastructure
|
14
14
|
in place, even if it's in the form of an "immediate runner". We can then have
|
data/lib/active_job/arguments.rb
CHANGED
@@ -7,7 +7,7 @@ module ActiveJob
|
|
7
7
|
#
|
8
8
|
# Wraps the original exception raised as +cause+.
|
9
9
|
class DeserializationError < StandardError
|
10
|
-
def initialize
|
10
|
+
def initialize # :nodoc:
|
11
11
|
super("Error while trying to deserialize arguments: #{$!.message}")
|
12
12
|
set_backtrace $!.backtrace
|
13
13
|
end
|
@@ -17,8 +17,8 @@ module ActiveJob
|
|
17
17
|
# currently support String, Integer, Float, NilClass, TrueClass, FalseClass,
|
18
18
|
# BigDecimal, Symbol, Date, Time, DateTime, ActiveSupport::TimeWithZone,
|
19
19
|
# ActiveSupport::Duration, Hash, ActiveSupport::HashWithIndifferentAccess,
|
20
|
-
# Array or GlobalID::Identification instances, although this can be
|
21
|
-
# by adding custom serializers.
|
20
|
+
# Array, Range or GlobalID::Identification instances, although this can be
|
21
|
+
# extended by adding custom serializers.
|
22
22
|
# Raised if you set the key for a Hash something else than a string or
|
23
23
|
# a symbol. Also raised when trying to serialize an object which can't be
|
24
24
|
# identified with a GlobalID - such as an unpersisted Active Record model.
|
@@ -73,24 +73,19 @@ module ActiveJob
|
|
73
73
|
using Module.new {
|
74
74
|
refine Hash do
|
75
75
|
class << Hash
|
76
|
-
|
77
|
-
|
78
|
-
!new(*[hash]).default.equal?(hash)
|
79
|
-
end
|
80
|
-
else
|
81
|
-
def ruby2_keywords_hash?(hash)
|
82
|
-
false
|
83
|
-
end
|
76
|
+
def ruby2_keywords_hash?(hash)
|
77
|
+
!new(*[hash]).default.equal?(hash)
|
84
78
|
end
|
85
79
|
|
86
80
|
def ruby2_keywords_hash(hash)
|
87
81
|
_ruby2_keywords_hash(**hash)
|
88
82
|
end
|
89
83
|
|
90
|
-
private
|
91
|
-
args
|
92
|
-
|
93
|
-
|
84
|
+
private
|
85
|
+
def _ruby2_keywords_hash(*args)
|
86
|
+
args.last
|
87
|
+
end
|
88
|
+
ruby2_keywords(:_ruby2_keywords_hash)
|
94
89
|
end
|
95
90
|
end
|
96
91
|
}
|
data/lib/active_job/base.rb
CHANGED
@@ -14,7 +14,7 @@ require "active_job/instrumentation"
|
|
14
14
|
require "active_job/timezones"
|
15
15
|
require "active_job/translation"
|
16
16
|
|
17
|
-
module ActiveJob
|
17
|
+
module ActiveJob # :nodoc:
|
18
18
|
# = Active Job
|
19
19
|
#
|
20
20
|
# Active Job objects can be configured to work with different backend
|
@@ -69,8 +69,8 @@ module ActiveJob #:nodoc:
|
|
69
69
|
include Execution
|
70
70
|
include Callbacks
|
71
71
|
include Exceptions
|
72
|
-
include Logging
|
73
72
|
include Instrumentation
|
73
|
+
include Logging
|
74
74
|
include Timezones
|
75
75
|
include Translation
|
76
76
|
|
data/lib/active_job/callbacks.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/callbacks"
|
4
|
-
require "active_support/core_ext/object/with_options"
|
5
4
|
require "active_support/core_ext/module/attribute_accessors"
|
6
5
|
|
7
6
|
module ActiveJob
|
@@ -30,24 +29,16 @@ module ActiveJob
|
|
30
29
|
|
31
30
|
included do
|
32
31
|
class_attribute :return_false_on_aborted_enqueue, instance_accessor: false, instance_predicate: false, default: false
|
33
|
-
singleton_class.deprecate :return_false_on_aborted_enqueue, :return_false_on_aborted_enqueue=
|
34
32
|
cattr_accessor :skip_after_callbacks_if_terminated, instance_accessor: false, default: false
|
33
|
+
singleton_class.deprecate :skip_after_callbacks_if_terminated, :skip_after_callbacks_if_terminated=
|
35
34
|
|
36
|
-
|
37
|
-
|
38
|
-
define_callbacks :enqueue
|
39
|
-
end
|
35
|
+
define_callbacks :perform, skip_after_callbacks_if_terminated: true
|
36
|
+
define_callbacks :enqueue, skip_after_callbacks_if_terminated: true
|
40
37
|
end
|
41
38
|
|
42
39
|
# These methods will be included into any Active Job object, adding
|
43
40
|
# callbacks for +perform+ and +enqueue+ methods.
|
44
41
|
module ClassMethods
|
45
|
-
def inherited(klass)
|
46
|
-
klass.get_callbacks(:enqueue).config[:skip_after_callbacks_if_terminated] = skip_after_callbacks_if_terminated
|
47
|
-
klass.get_callbacks(:perform).config[:skip_after_callbacks_if_terminated] = skip_after_callbacks_if_terminated
|
48
|
-
super
|
49
|
-
end
|
50
|
-
|
51
42
|
# Defines a callback that will get called right before the
|
52
43
|
# job's perform method is executed.
|
53
44
|
#
|
@@ -178,21 +169,5 @@ module ActiveJob
|
|
178
169
|
set_callback(:enqueue, :around, *filters, &blk)
|
179
170
|
end
|
180
171
|
end
|
181
|
-
|
182
|
-
private
|
183
|
-
def halted_callback_hook(_filter, name) # :nodoc:
|
184
|
-
return super unless %i(enqueue perform).include?(name.to_sym)
|
185
|
-
callbacks = public_send("_#{name}_callbacks")
|
186
|
-
|
187
|
-
if !self.class.skip_after_callbacks_if_terminated && callbacks.any? { |c| c.kind == :after }
|
188
|
-
ActiveSupport::Deprecation.warn(<<~EOM)
|
189
|
-
In Rails 6.2, `after_enqueue`/`after_perform` callbacks no longer run if `before_enqueue`/`before_perform` respectively halts with `throw :abort`.
|
190
|
-
To enable this behavior, uncomment the `config.active_job.skip_after_callbacks_if_terminated` config
|
191
|
-
in the new 6.1 framework defaults initializer.
|
192
|
-
EOM
|
193
|
-
end
|
194
|
-
|
195
|
-
super
|
196
|
-
end
|
197
172
|
end
|
198
173
|
end
|
@@ -1,20 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveJob
|
4
|
-
class ConfiguredJob
|
4
|
+
class ConfiguredJob # :nodoc:
|
5
5
|
def initialize(job_class, options = {})
|
6
6
|
@options = options
|
7
7
|
@job_class = job_class
|
8
8
|
end
|
9
9
|
|
10
|
-
def perform_now(
|
11
|
-
@job_class.new(
|
10
|
+
def perform_now(...)
|
11
|
+
@job_class.new(...).set(@options).perform_now
|
12
12
|
end
|
13
|
-
ruby2_keywords(:perform_now) if respond_to?(:ruby2_keywords, true)
|
14
13
|
|
15
|
-
def perform_later(
|
16
|
-
@job_class.new(
|
14
|
+
def perform_later(...)
|
15
|
+
@job_class.new(...).enqueue @options
|
17
16
|
end
|
18
|
-
ruby2_keywords(:perform_later) if respond_to?(:ruby2_keywords, true)
|
19
17
|
end
|
20
18
|
end
|
data/lib/active_job/core.rb
CHANGED
@@ -43,6 +43,16 @@ module ActiveJob
|
|
43
43
|
# Track when a job was enqueued
|
44
44
|
attr_accessor :enqueued_at
|
45
45
|
|
46
|
+
# Track whether the adapter received the job successfully.
|
47
|
+
attr_writer :successfully_enqueued # :nodoc:
|
48
|
+
|
49
|
+
def successfully_enqueued?
|
50
|
+
@successfully_enqueued
|
51
|
+
end
|
52
|
+
|
53
|
+
# Track any exceptions raised by the backend so callers can inspect the errors.
|
54
|
+
attr_accessor :enqueue_error
|
55
|
+
|
46
56
|
# These methods will be included into any Active Job object, adding
|
47
57
|
# helpers for de/serialization and creation of job instances.
|
48
58
|
module ClassMethods
|
@@ -87,7 +97,7 @@ module ActiveJob
|
|
87
97
|
@exception_executions = {}
|
88
98
|
@timezone = Time.zone&.name
|
89
99
|
end
|
90
|
-
ruby2_keywords(:initialize)
|
100
|
+
ruby2_keywords(:initialize)
|
91
101
|
|
92
102
|
# Returns a hash with the job data that can safely be passed to the
|
93
103
|
# queuing adapter.
|
@@ -146,6 +156,16 @@ module ActiveJob
|
|
146
156
|
self.enqueued_at = job_data["enqueued_at"]
|
147
157
|
end
|
148
158
|
|
159
|
+
# Configures the job with the given options.
|
160
|
+
def set(options = {}) # :nodoc:
|
161
|
+
self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait]
|
162
|
+
self.scheduled_at = options[:wait_until].to_f if options[:wait_until]
|
163
|
+
self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue]
|
164
|
+
self.priority = options[:priority].to_i if options[:priority]
|
165
|
+
|
166
|
+
self
|
167
|
+
end
|
168
|
+
|
149
169
|
private
|
150
170
|
def serialize_arguments_if_needed(arguments)
|
151
171
|
if arguments_serialized?
|
data/lib/active_job/enqueuing.rb
CHANGED
@@ -4,6 +4,11 @@ require "active_job/arguments"
|
|
4
4
|
|
5
5
|
module ActiveJob
|
6
6
|
# Provides behavior for enqueuing jobs.
|
7
|
+
|
8
|
+
# Can be raised by adapters if they wish to communicate to the caller a reason
|
9
|
+
# why the adapter was unexpectedly unable to enqueue a job.
|
10
|
+
class EnqueueError < StandardError; end
|
11
|
+
|
7
12
|
module Enqueuing
|
8
13
|
extend ActiveSupport::Concern
|
9
14
|
|
@@ -12,22 +17,28 @@ module ActiveJob
|
|
12
17
|
# Push a job onto the queue. By default the arguments must be either String,
|
13
18
|
# Integer, Float, NilClass, TrueClass, FalseClass, BigDecimal, Symbol, Date,
|
14
19
|
# Time, DateTime, ActiveSupport::TimeWithZone, ActiveSupport::Duration,
|
15
|
-
# Hash, ActiveSupport::HashWithIndifferentAccess, Array or
|
20
|
+
# Hash, ActiveSupport::HashWithIndifferentAccess, Array, Range or
|
16
21
|
# GlobalID::Identification instances, although this can be extended by adding
|
17
22
|
# custom serializers.
|
18
23
|
#
|
19
24
|
# Returns an instance of the job class queued with arguments available in
|
20
|
-
# Job#arguments.
|
21
|
-
|
22
|
-
|
25
|
+
# Job#arguments or false if the enqueue did not succeed.
|
26
|
+
#
|
27
|
+
# After the attempted enqueue, the job will be yielded to an optional block.
|
28
|
+
def perform_later(...)
|
29
|
+
job = job_or_instantiate(...)
|
30
|
+
enqueue_result = job.enqueue
|
31
|
+
|
32
|
+
yield job if block_given?
|
33
|
+
|
34
|
+
enqueue_result
|
23
35
|
end
|
24
|
-
ruby2_keywords(:perform_later) if respond_to?(:ruby2_keywords, true)
|
25
36
|
|
26
37
|
private
|
27
38
|
def job_or_instantiate(*args) # :doc:
|
28
39
|
args.first.is_a?(self) ? args.first : new(*args)
|
29
40
|
end
|
30
|
-
ruby2_keywords(:job_or_instantiate)
|
41
|
+
ruby2_keywords(:job_or_instantiate)
|
31
42
|
end
|
32
43
|
|
33
44
|
# Enqueues the job to be performed by the queue adapter.
|
@@ -46,11 +57,8 @@ module ActiveJob
|
|
46
57
|
# my_job_instance.enqueue wait_until: Date.tomorrow.midnight
|
47
58
|
# my_job_instance.enqueue priority: 10
|
48
59
|
def enqueue(options = {})
|
49
|
-
|
50
|
-
self.
|
51
|
-
self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue]
|
52
|
-
self.priority = options[:priority].to_i if options[:priority]
|
53
|
-
successfully_enqueued = false
|
60
|
+
set(options)
|
61
|
+
self.successfully_enqueued = false
|
54
62
|
|
55
63
|
run_callbacks :enqueue do
|
56
64
|
if scheduled_at
|
@@ -59,10 +67,12 @@ module ActiveJob
|
|
59
67
|
queue_adapter.enqueue self
|
60
68
|
end
|
61
69
|
|
62
|
-
successfully_enqueued = true
|
70
|
+
self.successfully_enqueued = true
|
71
|
+
rescue EnqueueError => e
|
72
|
+
self.enqueue_error = e
|
63
73
|
end
|
64
74
|
|
65
|
-
if successfully_enqueued
|
75
|
+
if successfully_enqueued?
|
66
76
|
self
|
67
77
|
else
|
68
78
|
false
|
@@ -25,7 +25,8 @@ module ActiveJob
|
|
25
25
|
# as a computing proc that takes the number of executions so far as an argument, or as a symbol reference of
|
26
26
|
# <tt>:exponentially_longer</tt>, which applies the wait algorithm of <tt>((executions**4) + (Kernel.rand * (executions**4) * jitter)) + 2</tt>
|
27
27
|
# (first wait ~3s, then ~18s, then ~83s, etc)
|
28
|
-
# * <tt>:attempts</tt> - Re-enqueues the job the specified number of times (default: 5 attempts)
|
28
|
+
# * <tt>:attempts</tt> - Re-enqueues the job the specified number of times (default: 5 attempts) or a symbol reference of <tt>:unlimited</tt>
|
29
|
+
# to retry the job until it succeeds
|
29
30
|
# * <tt>:queue</tt> - Re-enqueues the job on a different queue
|
30
31
|
# * <tt>:priority</tt> - Re-enqueues the job with a different priority
|
31
32
|
# * <tt>:jitter</tt> - A random delay of wait time used when calculating backoff. The default is 15% (0.15) which represents the upper bound of possible wait time (expressed as a percentage)
|
@@ -35,6 +36,7 @@ module ActiveJob
|
|
35
36
|
# class RemoteServiceJob < ActiveJob::Base
|
36
37
|
# retry_on CustomAppException # defaults to ~3s wait, 5 attempts
|
37
38
|
# retry_on AnotherCustomAppException, wait: ->(executions) { executions * 2 }
|
39
|
+
# retry_on CustomInfrastructureException, wait: 5.minutes, attempts: :unlimited
|
38
40
|
#
|
39
41
|
# retry_on ActiveRecord::Deadlocked, wait: 5.seconds, attempts: 3
|
40
42
|
# retry_on Net::OpenTimeout, Timeout::Error, wait: :exponentially_longer, attempts: 10 # retries at most 10 times for Net::OpenTimeout and Timeout::Error combined
|
@@ -56,7 +58,7 @@ module ActiveJob
|
|
56
58
|
def retry_on(*exceptions, wait: 3.seconds, attempts: 5, queue: nil, priority: nil, jitter: JITTER_DEFAULT)
|
57
59
|
rescue_from(*exceptions) do |error|
|
58
60
|
executions = executions_for(exceptions)
|
59
|
-
if executions < attempts
|
61
|
+
if attempts == :unlimited || executions < attempts
|
60
62
|
retry_job wait: determine_delay(seconds_or_duration_or_algorithm: wait, executions: executions, jitter: jitter), queue: queue, priority: priority, error: error
|
61
63
|
else
|
62
64
|
if block_given?
|
data/lib/active_job/execution.rb
CHANGED
@@ -14,12 +14,11 @@ module ActiveJob
|
|
14
14
|
#
|
15
15
|
# MyJob.perform_now("mike")
|
16
16
|
#
|
17
|
-
def perform_now(
|
18
|
-
job_or_instantiate(
|
17
|
+
def perform_now(...)
|
18
|
+
job_or_instantiate(...).perform_now
|
19
19
|
end
|
20
|
-
ruby2_keywords(:perform_now) if respond_to?(:ruby2_keywords, true)
|
21
20
|
|
22
|
-
def execute(job_data)
|
21
|
+
def execute(job_data) # :nodoc:
|
23
22
|
ActiveJob::Callbacks.run_callbacks(:execute) do
|
24
23
|
job = deserialize(job_data)
|
25
24
|
job.perform_now
|
@@ -44,15 +43,21 @@ module ActiveJob
|
|
44
43
|
|
45
44
|
deserialize_arguments_if_needed
|
46
45
|
|
47
|
-
|
48
|
-
|
49
|
-
end
|
50
|
-
rescue => exception
|
46
|
+
_perform_job
|
47
|
+
rescue Exception => exception
|
51
48
|
rescue_with_handler(exception) || raise
|
52
49
|
end
|
53
50
|
|
54
51
|
def perform(*)
|
55
52
|
fail NotImplementedError
|
56
53
|
end
|
54
|
+
|
55
|
+
private
|
56
|
+
def _perform_job
|
57
|
+
ActiveSupport::ExecutionContext[:job] = self
|
58
|
+
run_callbacks :perform do
|
59
|
+
perform(*arguments)
|
60
|
+
end
|
61
|
+
end
|
57
62
|
end
|
58
63
|
end
|
@@ -1,21 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveJob
|
4
|
-
module Instrumentation
|
4
|
+
module Instrumentation # :nodoc:
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
included do
|
8
8
|
around_enqueue do |_, block|
|
9
9
|
scheduled_at ? instrument(:enqueue_at, &block) : instrument(:enqueue, &block)
|
10
10
|
end
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
instrument :perform, &block
|
15
|
-
end
|
13
|
+
def perform_now
|
14
|
+
instrument(:perform) { super }
|
16
15
|
end
|
17
16
|
|
18
17
|
private
|
18
|
+
def _perform_job
|
19
|
+
instrument(:perform_start)
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
19
23
|
def instrument(operation, payload = {}, &block)
|
20
24
|
enhanced_block = ->(event_payload) do
|
21
25
|
value = block.call if block
|
@@ -4,7 +4,7 @@ require "active_support/core_ext/string/filters"
|
|
4
4
|
require "active_support/log_subscriber"
|
5
5
|
|
6
6
|
module ActiveJob
|
7
|
-
class LogSubscriber < ActiveSupport::LogSubscriber
|
7
|
+
class LogSubscriber < ActiveSupport::LogSubscriber # :nodoc:
|
8
8
|
def enqueue(event)
|
9
9
|
job = event.payload[:job]
|
10
10
|
ex = event.payload[:exception_object]
|