activejob 6.1.4.1 → 7.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +46 -136
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +3 -3
  5. data/lib/active_job/arguments.rb +10 -15
  6. data/lib/active_job/base.rb +2 -2
  7. data/lib/active_job/callbacks.rb +3 -28
  8. data/lib/active_job/configured_job.rb +5 -7
  9. data/lib/active_job/core.rb +21 -1
  10. data/lib/active_job/enqueuing.rb +23 -13
  11. data/lib/active_job/exceptions.rb +4 -2
  12. data/lib/active_job/execution.rb +13 -8
  13. data/lib/active_job/gem_version.rb +4 -4
  14. data/lib/active_job/instrumentation.rb +9 -5
  15. data/lib/active_job/log_subscriber.rb +1 -1
  16. data/lib/active_job/logging.rb +8 -5
  17. data/lib/active_job/queue_adapter.rb +1 -1
  18. data/lib/active_job/queue_adapters/async_adapter.rb +6 -6
  19. data/lib/active_job/queue_adapters/backburner_adapter.rb +3 -3
  20. data/lib/active_job/queue_adapters/delayed_job_adapter.rb +14 -4
  21. data/lib/active_job/queue_adapters/inline_adapter.rb +2 -2
  22. data/lib/active_job/queue_adapters/que_adapter.rb +3 -3
  23. data/lib/active_job/queue_adapters/queue_classic_adapter.rb +3 -3
  24. data/lib/active_job/queue_adapters/resque_adapter.rb +3 -3
  25. data/lib/active_job/queue_adapters/sidekiq_adapter.rb +3 -3
  26. data/lib/active_job/queue_adapters/sneakers_adapter.rb +3 -3
  27. data/lib/active_job/queue_adapters/sucker_punch_adapter.rb +3 -3
  28. data/lib/active_job/queue_adapters/test_adapter.rb +3 -2
  29. data/lib/active_job/queue_name.rb +1 -1
  30. data/lib/active_job/railtie.rb +22 -1
  31. data/lib/active_job/serializers/module_serializer.rb +1 -0
  32. data/lib/active_job/serializers/range_serializer.rb +23 -0
  33. data/lib/active_job/serializers.rb +3 -1
  34. data/lib/active_job/test_helper.rb +37 -13
  35. data/lib/active_job/timezones.rb +1 -1
  36. data/lib/active_job/translation.rb +1 -1
  37. data/lib/active_job.rb +2 -1
  38. metadata +12 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6b03cea30b4849af60c5253211f45e021d6c8e1e70c35df69e3ccd8c5332b305
4
- data.tar.gz: bb7b4b086c54dc2fc7f86e119691d2760e28277460731533546450e358005fae
3
+ metadata.gz: 17cac455c9915a33b6647a99cdf8b6a8a8618b7c4a239a91ec82b39cde3cb0e2
4
+ data.tar.gz: ba1ef66717563ae404620dfe54944321303838a2d07a88d74e0994b9a1fc5282
5
5
  SHA512:
6
- metadata.gz: 6f182060be4d5805c77f02c38005814dda1ba0f88487a3f9918788d55a096e98f78f43579aab1f627d3db25bb9e6cfbba0d6684924e20396cd4ea29a8ece193f
7
- data.tar.gz: 56b9a9114acb94a07bd047ae8945949483778f2c92d2bcea29ab03cf8e64f11444f9dd08f8b5bf5cb107fec233a900f916421c01a099bc63ae0c979bd107961a
6
+ metadata.gz: d794eac83e855f9528dab58acd501e2cd46b19656d0616746c9e9c082207587865bad42e54198412115696a0d5aa205a9ed4fe393eac18477d791cdabd878fdb
7
+ data.tar.gz: 69aa85dbcfa9621c225ee97a761352e45eaf55b41ebf4c5a9898d6eb18a36769c5ae0c3c5b207bf131cb0f60c5aef04ea9cf9c71803d4835cfdabc33624e31e9
data/CHANGELOG.md CHANGED
@@ -1,176 +1,86 @@
1
- ## Rails 6.1.4.1 (August 19, 2021) ##
2
-
3
- * No changes.
4
-
5
-
6
- ## Rails 6.1.4 (June 24, 2021) ##
7
-
8
- * No changes.
9
-
10
-
11
- ## Rails 6.1.3.2 (May 05, 2021) ##
12
-
13
- * No changes.
14
-
15
-
16
- ## Rails 6.1.3.1 (March 26, 2021) ##
17
-
18
- * No changes.
19
-
20
-
21
- ## Rails 6.1.3 (February 17, 2021) ##
22
-
23
- * No changes.
24
-
25
-
26
- ## Rails 6.1.2.1 (February 10, 2021) ##
27
-
28
- * No changes.
29
-
30
-
31
- ## Rails 6.1.2 (February 09, 2021) ##
32
-
33
- * No changes.
1
+ ## Rails 7.0.0.rc2 (December 14, 2021) ##
34
2
 
35
-
36
- ## Rails 6.1.1 (January 07, 2021) ##
37
-
38
- * Make `retry_job` return the job that was created.
3
+ * Remove deprecated `:return_false_on_aborted_enqueue` option.
39
4
 
40
5
  *Rafael Mendonça França*
41
6
 
42
- * Include `ActiveSupport::Testing::Assertions` in `ActiveJob::TestHelpers`.
43
-
44
- *Mikkel Malmberg*
45
-
46
-
47
- ## Rails 6.1.0 (December 09, 2020) ##
48
-
49
- * Recover nano precision when serializing `Time`, `TimeWithZone` and `DateTime` objects.
50
-
51
- *Alan Tan*
52
-
53
- * Deprecate `config.active_job.return_false_on_aborted_enqueue`.
7
+ * Deprecated `Rails.config.active_job.skip_after_callbacks_if_terminated`.
54
8
 
55
9
  *Rafael Mendonça França*
56
10
 
57
- * Return `false` when enqueuing a job is aborted.
11
+ * Removed deprecated behavior that was not halting `after_enqueue`/`after_perform` callbacks when a
12
+ previous callback was halted with `throw :abort`.
58
13
 
59
14
  *Rafael Mendonça França*
60
15
 
61
- * While using `perform_enqueued_jobs` test helper enqueued jobs must be stored for the later check with
62
- `assert_enqueued_with`.
63
-
64
- *Dmitry Polushkin*
65
-
66
- * `ActiveJob::TestCase#perform_enqueued_jobs` without a block removes performed jobs from the queue.
16
+ * Raise an `SerializationError` in `Serializer::ModuleSerializer`
17
+ if the module name is not present.
67
18
 
68
- That way the helper can be called multiple times and not perform a job invocation multiple times.
19
+ *Veerpal Brar*
69
20
 
70
- ```ruby
71
- def test_jobs
72
- HelloJob.perform_later("rafael")
73
- perform_enqueued_jobs # only runs with "rafael"
74
- HelloJob.perform_later("david")
75
- perform_enqueued_jobs # only runs with "david"
76
- end
77
- ```
78
21
 
79
- *Étienne Barrié*
22
+ ## Rails 7.0.0.alpha2 (September 15, 2021) ##
80
23
 
81
- * `ActiveJob::TestCase#perform_enqueued_jobs` will no longer perform retries:
82
-
83
- When calling `perform_enqueued_jobs` without a block, the adapter will
84
- now perform jobs that are **already** in the queue. Jobs that will end up in
85
- the queue afterwards won't be performed.
24
+ * No changes.
86
25
 
87
- This change only affects `perform_enqueued_jobs` when no block is given.
88
26
 
89
- *Edouard Chin*
27
+ ## Rails 7.0.0.alpha1 (September 15, 2021) ##
90
28
 
91
- * Add queue name support to Que adapter.
29
+ * Allow a job to retry indefinitely
92
30
 
93
- *Brad Nauta*, *Wojciech Wnętrzak*
31
+ The `attempts` parameter of the `retry_on` method now accepts the
32
+ symbol reference `:unlimited` in addition to a specific number of retry
33
+ attempts to allow a developer to specify that a job should retry
34
+ forever until it succeeds.
94
35
 
95
- * Don't run `after_enqueue` and `after_perform` callbacks if the callback chain is halted.
36
+ class MyJob < ActiveJob::Base
37
+ retry_on(AlwaysRetryException, attempts: :unlimited)
96
38
 
97
- class MyJob < ApplicationJob
98
- before_enqueue { throw(:abort) }
99
- after_enqueue { # won't enter here anymore }
39
+ # the actual job code
100
40
  end
101
41
 
102
- `after_enqueue` and `after_perform` callbacks will no longer run if the callback chain is halted.
103
- This behaviour is a breaking change and won't take effect until Rails 6.2.
104
- To enable this behaviour in your app right now, you can add in your app's configuration file
105
- `config.active_job.skip_after_callbacks_if_terminated = true`.
106
-
107
- *Edouard Chin*
42
+ *Daniel Morton*
108
43
 
109
- * Fix enqueuing and performing incorrect logging message.
44
+ * Added possibility to check on `:priority` in test helper methods
45
+ `assert_enqueued_with` and `assert_performed_with`.
110
46
 
111
- Jobs will no longer always log "Enqueued MyJob" or "Performed MyJob" when they actually didn't get enqueued/performed.
47
+ *Wojciech Wnętrzak*
112
48
 
113
- ```ruby
114
- class MyJob < ApplicationJob
115
- before_enqueue { throw(:abort) }
116
- end
49
+ * OpenSSL constants are now used for Digest computations.
117
50
 
118
- MyJob.perform_later # Will no longer log "Enqueued MyJob" since job wasn't even enqueued through adapter.
119
- ```
51
+ *Dirkjan Bussink*
120
52
 
121
- A new message will be logged in case a job couldn't be enqueued, either because the callback chain was halted or
122
- because an exception happened during enqueuing. (i.e. Redis is down when you try to enqueue your job)
53
+ * Add a Serializer for the Range class.
123
54
 
124
- *Edouard Chin*
55
+ This should allow things like `MyJob.perform_later(range: 1..100)`.
125
56
 
126
- * Add an option to disable logging of the job arguments when enqueuing and executing the job.
57
+ * Communicate enqueue failures to callers of `perform_later`.
127
58
 
128
- class SensitiveJob < ApplicationJob
129
- self.log_arguments = false
59
+ `perform_later` can now optionally take a block which will execute after
60
+ the adapter attempts to enqueue the job. The block will receive the job
61
+ instance as an argument even if the enqueue was not successful.
62
+ Additionally, `ActiveJob` adapters now have the ability to raise an
63
+ `ActiveJob::EnqueueError` which will be caught and stored in the job
64
+ instance so code attempting to enqueue jobs can inspect any raised
65
+ `EnqueueError` using the block.
130
66
 
131
- def perform(my_sensitive_argument)
67
+ MyJob.perform_later do |job|
68
+ unless job.successfully_enqueued?
69
+ if job.enqueue_error&.message == "Redis was unavailable"
70
+ # invoke some code that will retry the job after a delay
71
+ end
132
72
  end
133
73
  end
134
74
 
135
- When dealing with sensitive arguments as password and tokens it is now possible to configure the job
136
- to not put the sensitive argument in the logs.
137
-
138
- *Rafael Mendonça França*
139
-
140
- * Changes in `queue_name_prefix` of a job no longer affects all other jobs.
141
-
142
- Fixes #37084.
143
-
144
- *Lucas Mansur*
145
-
146
- * Allow `Class` and `Module` instances to be serialized.
147
-
148
- *Kevin Deisz*
149
-
150
- * Log potential matches in `assert_enqueued_with` and `assert_performed_with`.
151
-
152
- *Gareth du Plooy*
153
-
154
- * Add `at` argument to the `perform_enqueued_jobs` test helper.
155
-
156
- *John Crepezzi*, *Eileen Uchitelle*
157
-
158
- * `assert_enqueued_with` and `assert_performed_with` can now test jobs with relative delay.
159
-
160
- *Vlado Cingel*
75
+ *Daniel Morton*
161
76
 
162
- * Add jitter to `ActiveJob::Exceptions.retry_on`.
77
+ * Don't log rescuable exceptions defined with `rescue_from`.
163
78
 
164
- `ActiveJob::Exceptions.retry_on` now uses a random amount of jitter in order to
165
- prevent the [thundering herd effect](https://en.wikipedia.org/wiki/Thundering_herd_problem). Defaults to
166
- 15% (represented as 0.15) but overridable via the `:jitter` option when using `retry_on`.
167
- Jitter is applied when an `Integer`, `ActiveSupport::Duration` or `:exponentially_longer`, is passed to the `wait` argument in `retry_on`.
79
+ *Hu Hailin*
168
80
 
169
- ```ruby
170
- retry_on(MyError, wait: :exponentially_longer, jitter: 0.30)
171
- ```
81
+ * Allow `rescue_from` to rescue all exceptions.
172
82
 
173
- *Anthony Ross*
83
+ *Adrianna Chang*, *Étienne Barrié*
174
84
 
175
85
 
176
- Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/activejob/CHANGELOG.md) for previous changes.
86
+ Please check [6-1-stable](https://github.com/rails/rails/blob/6-1-stable/activejob/CHANGELOG.md) for previous changes.
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014-2020 David Heinemeier Hansson
1
+ Copyright (c) 2014-2021 David Heinemeier Hansson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
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. Anything that can be chopped up into
6
- small units of work and run in parallel, really.
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
- of the request-response cycle, so the user doesn't have to wait on it.
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
@@ -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 #:nodoc:
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 extended
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
- if RUBY_VERSION >= "2.7"
77
- def ruby2_keywords_hash?(hash)
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 def _ruby2_keywords_hash(*args)
91
- args.last
92
- end
93
- ruby2_keywords(:_ruby2_keywords_hash) if respond_to?(:ruby2_keywords, true)
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
  }
@@ -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 #:nodoc:
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
 
@@ -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
- with_options(skip_after_callbacks_if_terminated: skip_after_callbacks_if_terminated) do
37
- define_callbacks :perform
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 #:nodoc:
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(*args)
11
- @job_class.new(*args).perform_now
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(*args)
16
- @job_class.new(*args).enqueue @options
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
@@ -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) if respond_to?(:ruby2_keywords, true)
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?
@@ -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
- def perform_later(*args)
22
- job_or_instantiate(*args).enqueue
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) if respond_to?(:ruby2_keywords, true)
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
- self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait]
50
- self.scheduled_at = options[:wait_until].to_f if options[:wait_until]
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?
@@ -14,12 +14,11 @@ module ActiveJob
14
14
  #
15
15
  # MyJob.perform_now("mike")
16
16
  #
17
- def perform_now(*args)
18
- job_or_instantiate(*args).perform_now
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) #:nodoc:
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
- run_callbacks :perform do
48
- perform(*arguments)
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
@@ -7,10 +7,10 @@ module ActiveJob
7
7
  end
8
8
 
9
9
  module VERSION
10
- MAJOR = 6
11
- MINOR = 1
12
- TINY = 4
13
- PRE = "1"
10
+ MAJOR = 7
11
+ MINOR = 0
12
+ TINY = 0
13
+ PRE = "rc2"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -1,21 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveJob
4
- module Instrumentation #:nodoc:
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
- around_perform do |_, block|
13
- instrument :perform_start
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 #:nodoc:
7
+ class LogSubscriber < ActiveSupport::LogSubscriber # :nodoc:
8
8
  def enqueue(event)
9
9
  job = event.payload[:job]
10
10
  ex = event.payload[:exception_object]