activejob 6.1.4 → 7.0.0.rc1

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 +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]