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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -132
  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 +13 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c9a769fe2768c9eb83ad494a3df8b26563d79e227c2090aec92f3a72f219b6f5
4
- data.tar.gz: 74a40ff51687bf8fb48e2393e754f2ac8fb17ef38bf1bd0d3e8cadf4e2b46be8
3
+ metadata.gz: 4ae9afbd809eb16b45a08dd01c5a4b380bc0ce41055e074c0156ca1f0fae2650
4
+ data.tar.gz: 87653df366fcb02cead16d16a256fb99292cdce5f5a5504ceb2efe205378ca4a
5
5
  SHA512:
6
- metadata.gz: 943a0e1dcf505ccb814efb03ca3bed692aef6dc6adf5aacb228316d561cabe53fc1c211d6d659645797467b0adae1d639ce0e913973c0244bdd98f4a30203a56
7
- data.tar.gz: '0495568dfc65ca2ea01a2c11f087f0066b28dd103f2c948e76a13fc5d6ff2b853505c36b5a854a0b274b310968a499b9de824cbb7093a2a309f3490d48bc77b6'
6
+ metadata.gz: 07b924bedc982b2c43b7f0a75bdb3a9f0770730a17cb4c26a1dd553923ac2bcf5f9b186279e0d11d36975d3d128df27caaa1e3ca8d225a472c70b7fccbbfd219
7
+ data.tar.gz: 3bff03b822d41e5a88bf1e73273e09fa06f2ac311e508d1c99bfb72d852980beffed30e24b0cfdd1fa8fce9a05dd04b0ef108fb9ef9c66fe67fbfe0dda206475
data/CHANGELOG.md CHANGED
@@ -1,171 +1,84 @@
1
- ## Rails 6.1.4 (June 24, 2021) ##
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
- * Include `ActiveSupport::Testing::Assertions` in `ActiveJob::TestHelpers`.
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
- * Return `false` when enqueuing a job is aborted.
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
- * While using `perform_enqueued_jobs` test helper enqueued jobs must be stored for the later check with
57
- `assert_enqueued_with`.
14
+ * Raise an `SerializationError` in `Serializer::ModuleSerializer`
15
+ if the module name is not present.
58
16
 
59
- *Dmitry Polushkin*
17
+ *Veerpal Brar*
60
18
 
61
- * `ActiveJob::TestCase#perform_enqueued_jobs` without a block removes performed jobs from the queue.
62
19
 
63
- That way the helper can be called multiple times and not perform a job invocation multiple times.
20
+ ## Rails 7.0.0.alpha2 (September 15, 2021) ##
64
21
 
65
- ```ruby
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
- *Edouard Chin*
25
+ ## Rails 7.0.0.alpha1 (September 15, 2021) ##
85
26
 
86
- * Add queue name support to Que adapter.
27
+ * Allow a job to retry indefinitely
87
28
 
88
- *Brad Nauta*, *Wojciech Wnętrzak*
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
- * Don't run `after_enqueue` and `after_perform` callbacks if the callback chain is halted.
34
+ class MyJob < ActiveJob::Base
35
+ retry_on(AlwaysRetryException, attempts: :unlimited)
91
36
 
92
- class MyJob < ApplicationJob
93
- before_enqueue { throw(:abort) }
94
- after_enqueue { # won't enter here anymore }
37
+ # the actual job code
95
38
  end
96
39
 
97
- `after_enqueue` and `after_perform` callbacks will no longer run if the callback chain is halted.
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
- * Fix enqueuing and performing incorrect logging message.
42
+ * Added possibility to check on `:priority` in test helper methods
43
+ `assert_enqueued_with` and `assert_performed_with`.
105
44
 
106
- Jobs will no longer always log "Enqueued MyJob" or "Performed MyJob" when they actually didn't get enqueued/performed.
45
+ *Wojciech Wnętrzak*
107
46
 
108
- ```ruby
109
- class MyJob < ApplicationJob
110
- before_enqueue { throw(:abort) }
111
- end
47
+ * OpenSSL constants are now used for Digest computations.
112
48
 
113
- MyJob.perform_later # Will no longer log "Enqueued MyJob" since job wasn't even enqueued through adapter.
114
- ```
49
+ *Dirkjan Bussink*
115
50
 
116
- A new message will be logged in case a job couldn't be enqueued, either because the callback chain was halted or
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
- *Edouard Chin*
53
+ This should allow things like `MyJob.perform_later(range: 1..100)`.
120
54
 
121
- * Add an option to disable logging of the job arguments when enqueuing and executing the job.
55
+ * Communicate enqueue failures to callers of `perform_later`.
122
56
 
123
- class SensitiveJob < ApplicationJob
124
- self.log_arguments = false
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
- def perform(my_sensitive_argument)
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
- When dealing with sensitive arguments as password and tokens it is now possible to configure the job
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
- * Add jitter to `ActiveJob::Exceptions.retry_on`.
75
+ * Don't log rescuable exceptions defined with `rescue_from`.
158
76
 
159
- `ActiveJob::Exceptions.retry_on` now uses a random amount of jitter in order to
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
- ```ruby
165
- retry_on(MyError, wait: :exponentially_longer, jitter: 0.30)
166
- ```
79
+ * Allow `rescue_from` to rescue all exceptions.
167
80
 
168
- *Anthony Ross*
81
+ *Adrianna Chang*, *Étienne Barrié*
169
82
 
170
83
 
171
- Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/activejob/CHANGELOG.md) for previous changes.
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
@@ -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 = nil
10
+ MAJOR = 7
11
+ MINOR = 0
12
+ TINY = 0
13
+ PRE = "rc1"
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]