activejob 7.1.5 → 7.2.0.beta1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ae2dc7eee64d6fc1d387ddf668add362c3ceccd2e5b28810da74d898a5c790dc
4
- data.tar.gz: 2b00cf60b7d5b78ba4172497f4de8ad82db49a24cec20c6fffc09fdad8ff36d0
3
+ metadata.gz: 598d84beb0c743d639d0e0e6e152484a1695a82a4eeba838761755cb19602d9b
4
+ data.tar.gz: 7127ad30ef29ca6792aad06cdc13df5644dd9d3edb623860d6e65e0309d58006
5
5
  SHA512:
6
- metadata.gz: 7a9cab19419851bff44d21b65ba2b3f32d99c7a394a8e53ec6da7082d0f39d245d41526fee4f6048875b1a930eecbd3ef9e8dee6374b76237bc4cd753b34f59e
7
- data.tar.gz: 484654d35ba571afaab02ff30b8b61f2616227664a4fd3e0fe73ebf517e0c034a83119a19c07ada008b36d73a50f6b25dab54024667a1adf21cb5fad4aa28975
6
+ metadata.gz: c8cbfae1df6df13a75a277e51853ba3989fffdd29182f941c69d9d545f22aea966d9445f442681da4f272aa0c6e0fe4bd31f99489f99990ac2369ec688ddc94e
7
+ data.tar.gz: 5922b67c28a35052b2fa02c68b827689404622468dcacccf77326bf0bc4ea54d3e0f1d6db24f56737fefef6341f1b1d9a3b38b8acd4bd3add1d5b255fb6e722e
data/CHANGELOG.md CHANGED
@@ -1,305 +1,67 @@
1
- ## Rails 7.1.5 (October 30, 2024) ##
1
+ ## Rails 7.2.0.beta1 (May 29, 2024) ##
2
2
 
3
- * No changes.
3
+ * All tests now respect the `active_job.queue_adapter` config.
4
4
 
5
+ Previously if you had set `config.active_job.queue_adapter` in your `config/application.rb`
6
+ or `config/environments/test.rb` file, the adapter you selected was previously not used consistently
7
+ across all tests. In some tests your adapter would be used, but other tests would use the `TestAdapter`.
5
8
 
6
- ## Rails 7.1.4.2 (October 23, 2024) ##
9
+ In Rails 7.2, all tests will respect the `queue_adapter` config if provided. If no config is provided,
10
+ the `TestAdapter` will continue to be used.
7
11
 
8
- * No changes.
9
-
10
-
11
- ## Rails 7.1.4.1 (October 15, 2024) ##
12
-
13
- * No changes.
14
-
15
-
16
- ## Rails 7.1.4 (August 22, 2024) ##
17
-
18
- * Register autoload for `ActiveJob::Arguments`.
19
-
20
- *Rafael Mendonça França*
21
-
22
-
23
- ## Rails 7.1.3.4 (June 04, 2024) ##
24
-
25
- * No changes.
26
-
27
-
28
- ## Rails 7.1.3.3 (May 16, 2024) ##
29
-
30
- * No changes.
31
-
32
-
33
- ## Rails 7.1.3.2 (February 21, 2024) ##
34
-
35
- * No changes.
36
-
37
-
38
- ## Rails 7.1.3.1 (February 21, 2024) ##
39
-
40
- * No changes.
41
-
42
-
43
- ## Rails 7.1.3 (January 16, 2024) ##
44
-
45
- * Do not trigger immediate loading of `ActiveJob::Base` when loading `ActiveJob::TestHelper`.
46
-
47
- *Maxime Réty*
48
-
49
- * Preserve the serialized timezone when deserializing `ActiveSupport::TimeWithZone` arguments.
50
-
51
- *Joshua Young*
52
-
53
- * Fix ActiveJob arguments serialization to correctly serialize String subclasses having custom serializers.
54
-
55
- *fatkodima*
56
-
57
-
58
- ## Rails 7.1.2 (November 10, 2023) ##
59
-
60
- * No changes.
61
-
62
-
63
- ## Rails 7.1.1 (October 11, 2023) ##
64
-
65
- * Don't log enqueuing details when the job wasn't enqueued.
66
-
67
- *Dustin Brown*
68
-
69
-
70
- ## Rails 7.1.0 (October 05, 2023) ##
71
-
72
- * No changes.
73
-
74
-
75
- ## Rails 7.1.0.rc2 (October 01, 2023) ##
76
-
77
- * Make sure `scheduled_at` is a Time object when asserting enqueued jobs.
78
-
79
- *Rafael Mendonça França*
80
-
81
-
82
- ## Rails 7.1.0.rc1 (September 27, 2023) ##
83
-
84
- * Set `scheduled_at` attribute as a Time object instead of epoch seconds, and serialize and deserialize the value
85
- when enqueued. Assigning a numeric/epoch value to scheduled_at= is deprecated; use a Time object instead.
86
-
87
- Deserializes `enqueued_at` as a Time instead of ISO8601 String.
88
-
89
- *Ben Sheldon*
90
-
91
- * Clarify the backoff strategy for the recommended `:wait` option when retrying jobs
92
-
93
- `wait: :exponentially_longer` is waiting polynomially longer, so it is now recommended to use `wait: :polynomially_longer` to keep the same behavior.
94
-
95
- *Victor Mours*
96
-
97
-
98
- ## Rails 7.1.0.beta1 (September 13, 2023) ##
99
-
100
- * Fix Active Job log message to correctly report a job failed to enqueue
101
- when the adapter raises an `ActiveJob::EnqueueError`.
102
-
103
- *Ben Sheldon*
104
-
105
- * Add `after_discard` method.
106
-
107
- This method lets job authors define a block which will be run when a job is about to be discarded. For example:
108
-
109
- ```ruby
110
- class AfterDiscardJob < ActiveJob::Base
111
- after_discard do |job, exception|
112
- Rails.logger.info("#{job.class} raised an exception: #{exception}")
113
- end
114
-
115
- def perform
116
- raise StandardError
117
- end
118
- end
119
- ```
120
-
121
- The above job will run the block passed to `after_discard` after the job is discarded. The exception will
122
- still be raised after the block has been run.
123
-
124
- *Rob Cardy*
125
-
126
- * Fix deserialization of ActiveSupport::Duration
127
-
128
- Previously, a deserialized Duration would return an array from Duration#parts.
129
- It will now return a hash just like a regular Duration.
130
-
131
- This also fixes an error when trying to add or subtract from a deserialized Duration
132
- (eg `duration + 1.year`).
133
-
134
- *Jonathan del Strother*
135
-
136
- * `perform_enqueued_jobs` is now compatible with all Active Job adapters
137
-
138
- This means that methods that depend on it, like Action Mailer's `assert_emails`,
139
- will work correctly even if the test adapter is not used.
12
+ See [#48585](https://github.com/rails/rails/pull/48585) for more details.
140
13
 
141
14
  *Alex Ghiculescu*
142
15
 
143
- * Allow queue adapters to provide a custom name by implementing `queue_adapter_name`
144
-
145
- *Sander Verdonschot*
146
-
147
- * Log background job enqueue callers
148
-
149
- Add `verbose_enqueue_logs` configuration option to display the caller
150
- of background job enqueue in the log to help with debugging.
151
-
152
- Example log line:
153
-
154
- ```
155
- Enqueued AvatarThumbnailsJob (Job ID: ab528951-41fb-4c48-9129-3171791c27d6) to Sidekiq(default) with arguments: 1092412064
156
- ↳ app/models/user.rb:421:in `generate_avatar_thumbnails'
157
- ```
158
-
159
- Enabled in development only for new and upgraded applications. Not recommended for use
160
- in the production environment since it relies on Ruby's `Kernel#caller` which is fairly slow.
161
-
162
- *fatkodima*
163
-
164
- * Set `provider_job_id` for Backburner jobs
16
+ * Make Active Job transaction aware when used conjointly with Active Record.
165
17
 
166
- *Cameron Matheson*
167
-
168
- * Add `perform_all_later` to enqueue multiple jobs at once
169
-
170
- This adds the ability to bulk enqueue jobs, without running callbacks, by
171
- passing multiple jobs or an array of jobs. For example:
18
+ A common mistake with Active Job is to enqueue jobs from inside a transaction,
19
+ causing them to potentially be picked and ran by another process, before the
20
+ transaction is committed, which may result in various errors.
172
21
 
173
22
  ```ruby
174
- ActiveJob.perform_all_later(MyJob.new("hello", 42), MyJob.new("world", 0))
175
-
176
- user_jobs = User.pluck(:id).map { |id| UserJob.new(user_id: id) }
177
- ActiveJob.perform_all_later(user_jobs)
23
+ Topic.transaction do
24
+ topic = Topic.create(...)
25
+ NewTopicNotificationJob.perform_later(topic)
26
+ end
178
27
  ```
179
28
 
180
- This can greatly reduce the number of round-trips to the queue datastore.
181
- For queue adapters that do not implement the new `enqueue_all` method, we
182
- fall back to enqueuing jobs individually. The Sidekiq adapter implements
183
- `enqueue_all` with `push_bulk`.
184
-
185
- This method does not use the existing `enqueue.active_job` event, but adds a
186
- new event `enqueue_all.active_job`.
187
-
188
- *Sander Verdonschot*
189
-
190
- * Don't double log the `job` when using `ActiveRecord::QueryLog`
191
-
192
- Previously if you set `config.active_record.query_log_tags` to an array that included
193
- `:job`, the job name would get logged twice. This bug has been fixed.
194
-
195
- *Alex Ghiculescu*
196
-
197
- * Add support for Sidekiq's transaction-aware client
198
-
199
- *Jonathan del Strother*
29
+ Now Active Job will automatically defer the enqueuing to after the transaction is committed,
30
+ and drop the job if the transaction is rolled back.
200
31
 
201
- * Remove QueAdapter from Active Job.
202
-
203
- After maintaining Active Job QueAdapter by Rails and Que side
204
- to support Ruby 3 keyword arguments and options provided as top level keywords,
205
- it is quite difficult to maintain it this way.
206
-
207
- Active Job Que adapter can be included in the future version of que gem itself.
208
-
209
- *Yasuo Honda*
210
-
211
- * Fix BigDecimal (de)serialization for adapters using JSON.
212
-
213
- Previously, BigDecimal was listed as not needing a serializer. However,
214
- when used with an adapter storing the job arguments as JSON, it would get
215
- serialized as a simple String, resulting in deserialization also producing
216
- a String (instead of a BigDecimal).
217
-
218
- By using a serializer, we ensure the round trip is safe.
219
-
220
- To ensure applications using BigDecimal job arguments are not subject to
221
- race conditions during deployment (where a replica running a version of
222
- Rails without BigDecimalSerializer fails to deserialize an argument
223
- serialized with it), `ActiveJob.use_big_decimal_serializer` is disabled by
224
- default, and can be set to true in a following deployment..
225
-
226
- *Sam Bostock*
227
-
228
- * Preserve full-precision `enqueued_at` timestamps for serialized jobs,
229
- allowing more accurate reporting of how long a job spent waiting in the
230
- queue before it was performed.
231
-
232
- Retains IS08601 format compatibility.
233
-
234
- *Jeremy Daer*
235
-
236
- * Add `--parent` option to job generator to specify parent class of job.
237
-
238
- Example:
239
-
240
- `bin/rails g job process_payment --parent=payment_job` generates:
32
+ Various queue implementations can choose to disable this behavior, and users can disable it,
33
+ or force it on a per job basis:
241
34
 
242
35
  ```ruby
243
- class ProcessPaymentJob < PaymentJob
244
- # ...
36
+ class NewTopicNotificationJob < ApplicationJob
37
+ self.enqueue_after_transaction_commit = :never # or `:always` or `:default`
245
38
  end
246
39
  ```
247
40
 
248
- *Gannon McGibbon*
249
-
250
- * Add more detailed description to job generator.
251
-
252
- *Gannon McGibbon*
41
+ *Jean Boussier*, *Cristian Bica*
253
42
 
254
- * `perform.active_job` notification payloads now include `:db_runtime`, which
255
- is the total time (in ms) taken by database queries while performing a job.
256
- This value can be used to better understand how a job's time is spent.
257
-
258
- *Jonathan Hefner*
259
-
260
- * Update `ActiveJob::QueueAdapters::QueAdapter` to remove deprecation warning.
261
-
262
- Remove a deprecation warning introduced in que 1.2 to prepare for changes in
263
- que 2.0 necessary for Ruby 3 compatibility.
264
-
265
- *Damir Zekic* and *Adis Hasovic*
43
+ * Do not trigger immediate loading of `ActiveJob::Base` when loading `ActiveJob::TestHelper`.
266
44
 
267
- * Add missing `bigdecimal` require in `ActiveJob::Arguments`
45
+ *Maxime Réty*
268
46
 
269
- Could cause `uninitialized constant ActiveJob::Arguments::BigDecimal (NameError)`
270
- when loading Active Job in isolation.
47
+ * Preserve the serialized timezone when deserializing `ActiveSupport::TimeWithZone` arguments.
271
48
 
272
- *Jean Boussier*
49
+ *Joshua Young*
273
50
 
274
- * Allow testing `discard_on/retry_on ActiveJob::DeserializationError`
51
+ * Remove deprecated `:exponentially_longer` value for the `:wait` in `retry_on`.
275
52
 
276
- Previously in `perform_enqueued_jobs`, `deserialize_arguments_if_needed`
277
- was called before calling `perform_now`. When a record no longer exists
278
- and is serialized using GlobalID this led to raising
279
- an `ActiveJob::DeserializationError` before reaching `perform_now` call.
280
- This behavior makes difficult testing the job `discard_on/retry_on` logic.
53
+ *Rafael Mendonça França*
281
54
 
282
- Now `deserialize_arguments_if_needed` call is postponed to when `perform_now`
283
- is called.
55
+ * Remove deprecated support to set numeric values to `scheduled_at` attribute.
284
56
 
285
- Example:
57
+ *Rafael Mendonça França*
286
58
 
287
- ```ruby
288
- class UpdateUserJob < ActiveJob::Base
289
- discard_on ActiveJob::DeserializationError
59
+ * Deprecate `Rails.application.config.active_job.use_big_decimal_serialize`.
290
60
 
291
- def perform(user)
292
- # ...
293
- end
294
- end
61
+ *Rafael Mendonça França*
295
62
 
296
- # In the test
297
- User.destroy_all
298
- assert_nothing_raised do
299
- perform_enqueued_jobs only: UpdateUserJob
300
- end
301
- ```
63
+ * Remove deprecated primitive serializer for `BigDecimal` arguments.
302
64
 
303
- *Jacopo Beschi*
65
+ *Rafael Mendonça França*
304
66
 
305
- Please check [7-0-stable](https://github.com/rails/rails/blob/7-0-stable/activejob/CHANGELOG.md) for previous changes.
67
+ Please check [7-1-stable](https://github.com/rails/rails/blob/7-1-stable/activejob/CHANGELOG.md) for previous changes.
@@ -101,15 +101,6 @@ module ActiveJob
101
101
  else
102
102
  if argument.respond_to?(:permitted?) && argument.respond_to?(:to_h)
103
103
  serialize_indifferent_hash(argument.to_h)
104
- elsif BigDecimal === argument && !ActiveJob.use_big_decimal_serializer
105
- ActiveJob.deprecator.warn(<<~MSG)
106
- Primitive serialization of BigDecimal job arguments is deprecated as it may serialize via .to_s using certain queue adapters.
107
- Enable config.active_job.use_big_decimal_serializer to use BigDecimalSerializer instead, which will be mandatory in Rails 7.2.
108
-
109
- Note that if your application has multiple replicas, you should only enable this setting after successfully deploying your app to Rails 7.1 first.
110
- This will ensure that during your deployment all replicas are capable of deserializing arguments serialized with BigDecimalSerializer.
111
- MSG
112
- argument
113
104
  else
114
105
  Serializers.serialize(argument)
115
106
  end
@@ -120,8 +111,6 @@ module ActiveJob
120
111
  case argument
121
112
  when nil, true, false, String, Integer, Float
122
113
  argument
123
- when BigDecimal # BigDecimal may have been legacy serialized; Remove in 7.2
124
- argument
125
114
  when Array
126
115
  argument.map { |arg| deserialize_argument(arg) }
127
116
  when Hash
@@ -15,9 +15,6 @@ module ActiveJob
15
15
  # * <tt>before_perform</tt>
16
16
  # * <tt>around_perform</tt>
17
17
  # * <tt>after_perform</tt>
18
- #
19
- # NOTE: Calling the same callback multiple times will overwrite previous callback definitions.
20
- #
21
18
  module Callbacks
22
19
  extend ActiveSupport::Concern
23
20
  include ActiveSupport::Callbacks
@@ -13,9 +13,7 @@ module ActiveJob
13
13
  attr_writer :serialized_arguments
14
14
 
15
15
  # Time when the job should be performed
16
- attr_reader :scheduled_at
17
-
18
- attr_reader :_scheduled_at_time # :nodoc:
16
+ attr_accessor :scheduled_at
19
17
 
20
18
  # Job Identifier
21
19
  attr_accessor :job_id
@@ -97,7 +95,6 @@ module ActiveJob
97
95
  @job_id = SecureRandom.uuid
98
96
  @queue_name = self.class.queue_name
99
97
  @scheduled_at = nil
100
- @_scheduled_at_time = nil
101
98
  @priority = self.class.priority
102
99
  @executions = 0
103
100
  @exception_executions = {}
@@ -120,7 +117,7 @@ module ActiveJob
120
117
  "locale" => I18n.locale.to_s,
121
118
  "timezone" => timezone,
122
119
  "enqueued_at" => Time.now.utc.iso8601(9),
123
- "scheduled_at" => _scheduled_at_time ? _scheduled_at_time.utc.iso8601(9) : nil,
120
+ "scheduled_at" => scheduled_at ? scheduled_at.utc.iso8601(9) : nil,
124
121
  }
125
122
  end
126
123
 
@@ -174,18 +171,6 @@ module ActiveJob
174
171
  self
175
172
  end
176
173
 
177
- def scheduled_at=(value)
178
- @_scheduled_at_time = if value&.is_a?(Numeric)
179
- ActiveJob.deprecator.warn(<<~MSG.squish)
180
- Assigning a numeric/epoch value to scheduled_at is deprecated. Use a Time object instead.
181
- MSG
182
- Time.at(value)
183
- else
184
- value
185
- end
186
- @scheduled_at = value
187
- end
188
-
189
174
  private
190
175
  def serialize_arguments_if_needed(arguments)
191
176
  if arguments_serialized?
@@ -211,7 +196,7 @@ module ActiveJob
211
196
  end
212
197
 
213
198
  def arguments_serialized?
214
- defined?(@serialized_arguments) && @serialized_arguments
199
+ @serialized_arguments
215
200
  end
216
201
  end
217
202
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveJob
4
+ module EnqueueAfterTransactionCommit # :nodoc:
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ ##
9
+ # :singleton-method:
10
+ #
11
+ # Defines if enqueueing this job from inside an Active Record transaction
12
+ # automatically defers the enqueue to after the transaction commits.
13
+ #
14
+ # It can be set on a per job basis:
15
+ # - `:always` forces the job to be deferred.
16
+ # - `:never` forces the job to be queued immediately.
17
+ # - `:default` lets the queue adapter define the behavior (recommended).
18
+ class_attribute :enqueue_after_transaction_commit, instance_accessor: false, instance_predicate: false, default: :never
19
+ end
20
+
21
+ private
22
+ def raw_enqueue
23
+ after_transaction = case self.class.enqueue_after_transaction_commit
24
+ when :always
25
+ true
26
+ when :never
27
+ false
28
+ else # :default
29
+ queue_adapter.enqueue_after_transaction_commit?
30
+ end
31
+
32
+ if after_transaction
33
+ self.successfully_enqueued = true
34
+ ActiveRecord.after_all_transactions_commit do
35
+ self.successfully_enqueued = false
36
+ super
37
+ end
38
+ self
39
+ else
40
+ super
41
+ end
42
+ end
43
+ end
44
+ end
@@ -21,7 +21,7 @@ module ActiveJob
21
21
  adapter_jobs.each do |job|
22
22
  job.successfully_enqueued = false
23
23
  if job.scheduled_at
24
- queue_adapter.enqueue_at(job, job._scheduled_at_time.to_f)
24
+ queue_adapter.enqueue_at(job, job.scheduled_at.to_f)
25
25
  else
26
26
  queue_adapter.enqueue(job)
27
27
  end
@@ -50,9 +50,21 @@ module ActiveJob
50
50
  # custom serializers.
51
51
  #
52
52
  # Returns an instance of the job class queued with arguments available in
53
- # Job#arguments or false if the enqueue did not succeed.
53
+ # Job#arguments or +false+ if the enqueue did not succeed.
54
54
  #
55
55
  # After the attempted enqueue, the job will be yielded to an optional block.
56
+ #
57
+ # If Active Job is used conjointly with Active Record, and #perform_later is called
58
+ # inside an Active Record transaction, then the enqueue is implicitly deferred to after
59
+ # the transaction is committed, or dropped if it's rolled back. In such case #perform_later
60
+ # will return the job instance like if it was successfully enqueued, but will still return
61
+ # +false+ if a callback prevented the job from being enqueued.
62
+ #
63
+ # This behavior can be changed on a per job basis:
64
+ #
65
+ # class NotificationJob < ApplicationJob
66
+ # self.enqueue_after_transaction_commit = false
67
+ # end
56
68
  def perform_later(...)
57
69
  job = job_or_instantiate(...)
58
70
  enqueue_result = job.enqueue
@@ -63,7 +75,7 @@ module ActiveJob
63
75
  end
64
76
 
65
77
  private
66
- def job_or_instantiate(*args) # :doc:
78
+ def job_or_instantiate(*args, &_) # :doc:
67
79
  args.first.is_a?(self) ? args.first : new(*args)
68
80
  end
69
81
  ruby2_keywords(:job_or_instantiate)
@@ -89,8 +101,20 @@ module ActiveJob
89
101
  self.successfully_enqueued = false
90
102
 
91
103
  run_callbacks :enqueue do
104
+ raw_enqueue
105
+ end
106
+
107
+ if successfully_enqueued?
108
+ self
109
+ else
110
+ false
111
+ end
112
+ end
113
+
114
+ private
115
+ def raw_enqueue
92
116
  if scheduled_at
93
- queue_adapter.enqueue_at self, _scheduled_at_time.to_f
117
+ queue_adapter.enqueue_at self, scheduled_at.to_f
94
118
  else
95
119
  queue_adapter.enqueue self
96
120
  end
@@ -99,12 +123,5 @@ module ActiveJob
99
123
  rescue EnqueueError => e
100
124
  self.enqueue_error = e
101
125
  end
102
-
103
- if successfully_enqueued?
104
- self
105
- else
106
- false
107
- end
108
- end
109
126
  end
110
127
  end
@@ -21,7 +21,7 @@ module ActiveJob
21
21
  # You can also pass a block that'll be invoked if the retry attempts fail for custom logic rather than letting
22
22
  # the exception bubble up. This block is yielded with the job instance as the first and the error instance as the second parameter.
23
23
  #
24
- # `retry_on` and `discard_on` handlers are searched from bottom to top, and up the class hierarchy. The handler of the first class for
24
+ # +retry_on+ and +discard_on+ handlers are searched from bottom to top, and up the class hierarchy. The handler of the first class for
25
25
  # which <tt>exception.is_a?(klass)</tt> holds true is the one invoked, if any.
26
26
  #
27
27
  # ==== Options
@@ -29,8 +29,8 @@ module ActiveJob
29
29
  # as a computing proc that takes the number of executions so far as an argument, or as a symbol reference of
30
30
  # <tt>:polynomially_longer</tt>, which applies the wait algorithm of <tt>((executions**4) + (Kernel.rand * (executions**4) * jitter)) + 2</tt>
31
31
  # (first wait ~3s, then ~18s, then ~83s, etc)
32
- # * <tt>:attempts</tt> - Re-enqueues the job the specified number of times (default: 5 attempts) or a symbol reference of <tt>:unlimited</tt>
33
- # to retry the job until it succeeds
32
+ # * <tt>:attempts</tt> - Enqueues the job the specified number of times (default: 5 attempts) or a symbol reference of <tt>:unlimited</tt>
33
+ # to retry the job until it succeeds. The number of attempts includes the original job execution.
34
34
  # * <tt>:queue</tt> - Re-enqueues the job on a different queue
35
35
  # * <tt>:priority</tt> - Re-enqueues the job with a different priority
36
36
  # * <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)
@@ -60,12 +60,6 @@ module ActiveJob
60
60
  # end
61
61
  # end
62
62
  def retry_on(*exceptions, wait: 3.seconds, attempts: 5, queue: nil, priority: nil, jitter: JITTER_DEFAULT)
63
- if wait == :exponentially_longer
64
- ActiveJob.deprecator.warn(<<~MSG.squish)
65
- `wait: :exponentially_longer` will actually wait polynomially longer and is therefore deprecated.
66
- Prefer `wait: :polynomially_longer` to avoid confusion and keep the same behavior.
67
- MSG
68
- end
69
63
  rescue_from(*exceptions) do |error|
70
64
  executions = executions_for(exceptions)
71
65
  if attempts == :unlimited || executions < attempts
@@ -90,7 +84,7 @@ module ActiveJob
90
84
  #
91
85
  # You can also pass a block that'll be invoked. This block is yielded with the job instance as the first and the error instance as the second parameter.
92
86
  #
93
- # `retry_on` and `discard_on` handlers are searched from bottom to top, and up the class hierarchy. The handler of the first class for
87
+ # +retry_on+ and +discard_on+ handlers are searched from bottom to top, and up the class hierarchy. The handler of the first class for
94
88
  # which <tt>exception.is_a?(klass)</tt> holds true is the one invoked, if any.
95
89
  #
96
90
  # ==== Example
@@ -168,7 +162,7 @@ module ActiveJob
168
162
  jitter = jitter == JITTER_DEFAULT ? self.class.retry_jitter : (jitter || 0.0)
169
163
 
170
164
  case seconds_or_duration_or_algorithm
171
- when :exponentially_longer, :polynomially_longer
165
+ when :polynomially_longer
172
166
  # This delay uses a polynomial backoff strategy, which was previously misnamed as exponential
173
167
  delay = executions**4
174
168
  delay_jitter = determine_jitter_for_delay(delay, jitter)
@@ -8,9 +8,9 @@ module ActiveJob
8
8
 
9
9
  module VERSION
10
10
  MAJOR = 7
11
- MINOR = 1
12
- TINY = 5
13
- PRE = nil
11
+ MINOR = 2
12
+ TINY = 0
13
+ PRE = "beta1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -15,7 +15,8 @@ module ActiveJob
15
15
  # = Active Job Queue adapter
16
16
  #
17
17
  # The +ActiveJob::QueueAdapter+ module is used to load the
18
- # correct adapter. The default queue adapter is the +:async+ queue.
18
+ # correct adapter. The default queue adapter is +:async+,
19
+ # which loads the ActiveJob::QueueAdapters::AsyncAdapter.
19
20
  module QueueAdapter # :nodoc:
20
21
  extend ActiveSupport::Concern
21
22
 
@@ -24,21 +25,21 @@ module ActiveJob
24
25
  class_attribute :_queue_adapter, instance_accessor: false, instance_predicate: false
25
26
 
26
27
  delegate :queue_adapter, to: :class
27
-
28
- self.queue_adapter = :async
29
28
  end
30
29
 
31
30
  # Includes the setter method for changing the active queue adapter.
32
31
  module ClassMethods
33
32
  # Returns the backend queue provider. The default queue adapter
34
- # is the +:async+ queue. See QueueAdapters for more information.
33
+ # is +:async+. See QueueAdapters for more information.
35
34
  def queue_adapter
35
+ self.queue_adapter = :async if _queue_adapter.nil?
36
36
  _queue_adapter
37
37
  end
38
38
 
39
39
  # Returns string denoting the name of the configured queue adapter.
40
40
  # By default returns <tt>"async"</tt>.
41
41
  def queue_adapter_name
42
+ self.queue_adapter = :async if _queue_adapter_name.nil?
42
43
  _queue_adapter_name
43
44
  end
44
45
 
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveJob
4
+ module QueueAdapters
5
+ # = Active Job Abstract Adapter
6
+ #
7
+ # Active Job supports multiple job queue systems. ActiveJob::QueueAdapters::AbstractAdapter
8
+ # forms the abstraction layer which makes this possible.
9
+ class AbstractAdapter
10
+ # Defines whether enqueuing should happen implicitly to after commit when called
11
+ # from inside a transaction. Most adapters should return true, but some adapters
12
+ # that use the same database as Active Record and are transaction aware can return
13
+ # false to continue enqueuing jobs as part of the transaction.
14
+ def enqueue_after_transaction_commit?
15
+ true
16
+ end
17
+
18
+ def enqueue(job)
19
+ raise NotImplementedError
20
+ end
21
+
22
+ def enqueue_at(job, timestamp)
23
+ raise NotImplementedError
24
+ end
25
+ end
26
+ end
27
+ end
@@ -30,7 +30,7 @@ module ActiveJob
30
30
  # The adapter uses a {Concurrent Ruby}[https://github.com/ruby-concurrency/concurrent-ruby] thread pool to schedule and execute
31
31
  # jobs. Since jobs share a single thread pool, long-running jobs will block
32
32
  # short-lived jobs. Fine for dev/test; bad for production.
33
- class AsyncAdapter
33
+ class AsyncAdapter < AbstractAdapter
34
34
  # See {Concurrent::ThreadPoolExecutor}[https://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/ThreadPoolExecutor.html] for executor options.
35
35
  def initialize(**executor_options)
36
36
  @scheduler = Scheduler.new(**executor_options)
@@ -14,7 +14,7 @@ module ActiveJob
14
14
  # To use Backburner set the queue_adapter config to +:backburner+.
15
15
  #
16
16
  # Rails.application.config.active_job.queue_adapter = :backburner
17
- class BackburnerAdapter
17
+ class BackburnerAdapter < AbstractAdapter
18
18
  def enqueue(job) # :nodoc:
19
19
  response = Backburner::Worker.enqueue(JobWrapper, [job.serialize], queue: job.queue_name, pri: job.priority)
20
20
  job.provider_job_id = response[:id] if response.is_a?(Hash)
@@ -15,7 +15,15 @@ module ActiveJob
15
15
  # To use Delayed Job, set the queue_adapter config to +:delayed_job+.
16
16
  #
17
17
  # Rails.application.config.active_job.queue_adapter = :delayed_job
18
- class DelayedJobAdapter
18
+ class DelayedJobAdapter < AbstractAdapter
19
+ def initialize(enqueue_after_transaction_commit: false)
20
+ @enqueue_after_transaction_commit = enqueue_after_transaction_commit
21
+ end
22
+
23
+ def enqueue_after_transaction_commit? # :nodoc:
24
+ @enqueue_after_transaction_commit
25
+ end
26
+
19
27
  def enqueue(job) # :nodoc:
20
28
  delayed_job = Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name, priority: job.priority)
21
29
  job.provider_job_id = delayed_job.id
@@ -10,7 +10,11 @@ module ActiveJob
10
10
  # To use the Inline set the queue_adapter config to +:inline+.
11
11
  #
12
12
  # Rails.application.config.active_job.queue_adapter = :inline
13
- class InlineAdapter
13
+ class InlineAdapter < AbstractAdapter
14
+ def enqueue_after_transaction_commit? # :nodoc:
15
+ false
16
+ end
17
+
14
18
  def enqueue(job) # :nodoc:
15
19
  Base.execute(job.serialize)
16
20
  end
@@ -18,7 +18,15 @@ module ActiveJob
18
18
  # To use queue_classic set the queue_adapter config to +:queue_classic+.
19
19
  #
20
20
  # Rails.application.config.active_job.queue_adapter = :queue_classic
21
- class QueueClassicAdapter
21
+ class QueueClassicAdapter < AbstractAdapter
22
+ def initialize(enqueue_after_transaction_commit: false)
23
+ @enqueue_after_transaction_commit = enqueue_after_transaction_commit
24
+ end
25
+
26
+ def enqueue_after_transaction_commit? # :nodoc:
27
+ @enqueue_after_transaction_commit
28
+ end
29
+
22
30
  def enqueue(job) # :nodoc:
23
31
  qc_job = build_queue(job.queue_name).enqueue("#{JobWrapper.name}.perform", job.serialize)
24
32
  job.provider_job_id = qc_job["id"] if qc_job.is_a?(Hash)
@@ -27,7 +27,7 @@ module ActiveJob
27
27
  # To use Resque set the queue_adapter config to +:resque+.
28
28
  #
29
29
  # Rails.application.config.active_job.queue_adapter = :resque
30
- class ResqueAdapter
30
+ class ResqueAdapter < AbstractAdapter
31
31
  def enqueue(job) # :nodoc:
32
32
  JobWrapper.instance_variable_set(:@queue, job.queue_name)
33
33
  Resque.enqueue_to job.queue_name, JobWrapper, job.serialize
@@ -17,7 +17,7 @@ module ActiveJob
17
17
  # To use Sidekiq set the queue_adapter config to +:sidekiq+.
18
18
  #
19
19
  # Rails.application.config.active_job.queue_adapter = :sidekiq
20
- class SidekiqAdapter
20
+ class SidekiqAdapter < AbstractAdapter
21
21
  def enqueue(job) # :nodoc:
22
22
  job.provider_job_id = JobWrapper.set(
23
23
  wrapped: job.class,
@@ -17,7 +17,7 @@ module ActiveJob
17
17
  # To use Sneakers set the queue_adapter config to +:sneakers+.
18
18
  #
19
19
  # Rails.application.config.active_job.queue_adapter = :sneakers
20
- class SneakersAdapter
20
+ class SneakersAdapter < AbstractAdapter
21
21
  def initialize
22
22
  @monitor = Monitor.new
23
23
  end
@@ -17,7 +17,7 @@ module ActiveJob
17
17
  # To use Sucker Punch set the queue_adapter config to +:sucker_punch+.
18
18
  #
19
19
  # Rails.application.config.active_job.queue_adapter = :sucker_punch
20
- class SuckerPunchAdapter
20
+ class SuckerPunchAdapter < AbstractAdapter
21
21
  def enqueue(job) # :nodoc:
22
22
  if JobWrapper.respond_to?(:perform_async)
23
23
  # sucker_punch 2.0 API
@@ -11,10 +11,18 @@ module ActiveJob
11
11
  # To use the test adapter set +queue_adapter+ config to +:test+.
12
12
  #
13
13
  # Rails.application.config.active_job.queue_adapter = :test
14
- class TestAdapter
15
- attr_accessor(:perform_enqueued_jobs, :perform_enqueued_at_jobs, :filter, :reject, :queue, :at)
14
+ class TestAdapter < AbstractAdapter
15
+ attr_accessor(:perform_enqueued_jobs, :perform_enqueued_at_jobs, :filter, :reject, :queue, :at, :enqueue_after_transaction_commit)
16
16
  attr_writer(:enqueued_jobs, :performed_jobs)
17
17
 
18
+ def initialize(enqueue_after_transaction_commit: true)
19
+ @enqueue_after_transaction_commit = enqueue_after_transaction_commit
20
+ end
21
+
22
+ def enqueue_after_transaction_commit? # :nodoc:
23
+ @enqueue_after_transaction_commit
24
+ end
25
+
18
26
  # Provides a store of all the enqueued jobs with the TestAdapter so you can check them.
19
27
  def enqueued_jobs
20
28
  @enqueued_jobs ||= []
@@ -114,6 +114,7 @@ module ActiveJob
114
114
  module QueueAdapters
115
115
  extend ActiveSupport::Autoload
116
116
 
117
+ autoload :AbstractAdapter
117
118
  autoload :AsyncAdapter
118
119
  autoload :InlineAdapter
119
120
  autoload :BackburnerAdapter
@@ -25,9 +25,23 @@ module ActiveJob
25
25
  end
26
26
  end
27
27
 
28
+ initializer "active_job.enqueue_after_transaction_commit" do |app|
29
+ if config.active_job.key?(:enqueue_after_transaction_commit)
30
+ enqueue_after_transaction_commit = config.active_job.delete(:enqueue_after_transaction_commit)
31
+
32
+ ActiveSupport.on_load(:active_record) do
33
+ ActiveSupport.on_load(:active_job) do
34
+ include EnqueueAfterTransactionCommit
35
+
36
+ ActiveJob::Base.enqueue_after_transaction_commit = enqueue_after_transaction_commit
37
+ end
38
+ end
39
+ end
40
+ end
41
+
28
42
  initializer "active_job.set_configs" do |app|
29
43
  options = app.config.active_job
30
- options.queue_adapter ||= :async
44
+ options.queue_adapter ||= (Rails.env.test? ? :test : :async)
31
45
 
32
46
  config.after_initialize do
33
47
  options.each do |k, v|
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "singleton"
4
+
3
5
  module ActiveJob
4
6
  module Serializers
5
7
  # Base class for serializing and deserializing custom objects.
@@ -39,10 +39,13 @@ module ActiveJob
39
39
  end
40
40
 
41
41
  def before_setup # :nodoc:
42
- test_adapter = queue_adapter_for_test
43
-
42
+ queue_adapter_specific_to_this_test_class = queue_adapter_for_test
44
43
  queue_adapter_changed_jobs.each do |klass|
45
- klass.enable_test_adapter(test_adapter)
44
+ if queue_adapter_specific_to_this_test_class
45
+ klass.enable_test_adapter(queue_adapter_specific_to_this_test_class)
46
+ elsif klass._queue_adapter.nil?
47
+ klass.enable_test_adapter(ActiveJob::QueueAdapters::TestAdapter.new)
48
+ end
46
49
  end
47
50
 
48
51
  clear_enqueued_jobs
@@ -61,7 +64,6 @@ module ActiveJob
61
64
  # Override this method to specify a different adapter. The adapter must
62
65
  # implement the same interface as ActiveJob::QueueAdapters::TestAdapter.
63
66
  def queue_adapter_for_test
64
- ActiveJob::QueueAdapters::TestAdapter.new
65
67
  end
66
68
 
67
69
  # Asserts that the number of enqueued jobs matches the given number.
@@ -118,6 +120,8 @@ module ActiveJob
118
120
  # end
119
121
  # end
120
122
  def assert_enqueued_jobs(number, only: nil, except: nil, queue: nil, &block)
123
+ require_active_job_test_adapter!("assert_enqueued_jobs")
124
+
121
125
  if block_given?
122
126
  original_jobs = enqueued_jobs_with(only: only, except: except, queue: queue)
123
127
 
@@ -180,6 +184,8 @@ module ActiveJob
180
184
  #
181
185
  # assert_enqueued_jobs 0, &block
182
186
  def assert_no_enqueued_jobs(only: nil, except: nil, queue: nil, &block)
187
+ require_active_job_test_adapter!("assert_no_enqueued_jobs")
188
+
183
189
  assert_enqueued_jobs 0, only: only, except: except, queue: queue, &block
184
190
  end
185
191
 
@@ -270,6 +276,8 @@ module ActiveJob
270
276
  # end
271
277
  # end
272
278
  def assert_performed_jobs(number, only: nil, except: nil, queue: nil, &block)
279
+ require_active_job_test_adapter!("assert_performed_jobs")
280
+
273
281
  if block_given?
274
282
  original_count = performed_jobs.size
275
283
 
@@ -338,6 +346,8 @@ module ActiveJob
338
346
  #
339
347
  # assert_performed_jobs 0, &block
340
348
  def assert_no_performed_jobs(only: nil, except: nil, queue: nil, &block)
349
+ require_active_job_test_adapter!("assert_no_performed_jobs")
350
+
341
351
  assert_performed_jobs 0, only: only, except: except, queue: queue, &block
342
352
  end
343
353
 
@@ -394,6 +404,8 @@ module ActiveJob
394
404
  # end
395
405
  # end
396
406
  def assert_enqueued_with(job: nil, args: nil, at: nil, queue: nil, priority: nil, &block)
407
+ require_active_job_test_adapter!("assert_enqueued_with")
408
+
397
409
  expected = { job: job, args: args, at: at, queue: queue, priority: priority }.compact
398
410
  expected_args = prepare_args_for_assertion(expected)
399
411
  potential_matches = []
@@ -496,6 +508,8 @@ module ActiveJob
496
508
  # end
497
509
  # end
498
510
  def assert_performed_with(job: nil, args: nil, at: nil, queue: nil, priority: nil, &block)
511
+ require_active_job_test_adapter!("assert_performed_with")
512
+
499
513
  expected = { job: job, args: args, at: at, queue: queue, priority: priority }.compact
500
514
  expected_args = prepare_args_for_assertion(expected)
501
515
  potential_matches = []
@@ -604,7 +618,10 @@ module ActiveJob
604
618
  # If queue_adapter_for_test is overridden to return a different adapter,
605
619
  # +perform_enqueued_jobs+ will merely execute the block.
606
620
  def perform_enqueued_jobs(only: nil, except: nil, queue: nil, at: nil, &block)
607
- return flush_enqueued_jobs(only: only, except: except, queue: queue, at: at) unless block_given?
621
+ unless block_given?
622
+ require_active_job_test_adapter!("perform_enqueued_jobs (without a block)")
623
+ return flush_enqueued_jobs(only: only, except: except, queue: queue, at: at)
624
+ end
608
625
 
609
626
  return _assert_nothing_raised_or_warn("perform_enqueued_jobs", &block) unless using_test_adapter?
610
627
 
@@ -646,6 +663,12 @@ module ActiveJob
646
663
  end
647
664
 
648
665
  private
666
+ def require_active_job_test_adapter!(method)
667
+ unless using_test_adapter?
668
+ raise ArgumentError.new("#{method} requires the Active Job test adapter, you're using #{queue_adapter.class.name}.")
669
+ end
670
+ end
671
+
649
672
  def using_test_adapter?
650
673
  queue_adapter.is_a?(ActiveJob::QueueAdapters::TestAdapter)
651
674
  end
data/lib/active_job.rb CHANGED
@@ -39,6 +39,7 @@ module ActiveJob
39
39
  autoload :Arguments
40
40
  autoload :DeserializationError, "active_job/arguments"
41
41
  autoload :SerializationError, "active_job/arguments"
42
+ autoload :EnqueueAfterTransactionCommit
42
43
 
43
44
  eager_autoload do
44
45
  autoload :Serializers
@@ -48,16 +49,20 @@ module ActiveJob
48
49
  autoload :TestCase
49
50
  autoload :TestHelper
50
51
 
51
- ##
52
- # :singleton-method:
53
- # If false, \Rails will preserve the legacy serialization of BigDecimal job arguments as Strings.
54
- # If true, \Rails will use the new BigDecimalSerializer to (de)serialize BigDecimal losslessly.
55
- # Legacy serialization will be removed in \Rails 7.2, along with this config.
56
- singleton_class.attr_accessor :use_big_decimal_serializer
57
- self.use_big_decimal_serializer = false
52
+ def self.use_big_decimal_serializer
53
+ ActiveJob.deprecator.warn <<-WARNING.squish
54
+ Rails.application.config.active_job.use_big_decimal_serializer is deprecated and will be removed in Rails 7.3.
55
+ WARNING
56
+ end
57
+
58
+ def self.use_big_decimal_serializer=(value)
59
+ ActiveJob.deprecator.warn <<-WARNING.squish
60
+ Rails.application.config.active_job.use_big_decimal_serializer is deprecated and will be removed in Rails 7.3.
61
+ WARNING
62
+ end
58
63
 
59
64
  ##
60
- # :singleton-method:
65
+ # :singleton-method: verbose_enqueue_logs
61
66
  #
62
67
  # Specifies if the methods calling background job enqueue should be logged below
63
68
  # their relevant enqueue log lines. Defaults to false.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activejob
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.1.5
4
+ version: 7.2.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-31 00:00:00.000000000 Z
11
+ date: 2024-05-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 7.1.5
19
+ version: 7.2.0.beta1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 7.1.5
26
+ version: 7.2.0.beta1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: globalid
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -54,6 +54,7 @@ files:
54
54
  - lib/active_job/configured_job.rb
55
55
  - lib/active_job/core.rb
56
56
  - lib/active_job/deprecator.rb
57
+ - lib/active_job/enqueue_after_transaction_commit.rb
57
58
  - lib/active_job/enqueuing.rb
58
59
  - lib/active_job/exceptions.rb
59
60
  - lib/active_job/execution.rb
@@ -63,6 +64,7 @@ files:
63
64
  - lib/active_job/logging.rb
64
65
  - lib/active_job/queue_adapter.rb
65
66
  - lib/active_job/queue_adapters.rb
67
+ - lib/active_job/queue_adapters/abstract_adapter.rb
66
68
  - lib/active_job/queue_adapters/async_adapter.rb
67
69
  - lib/active_job/queue_adapters/backburner_adapter.rb
68
70
  - lib/active_job/queue_adapters/delayed_job_adapter.rb
@@ -102,12 +104,12 @@ licenses:
102
104
  - MIT
103
105
  metadata:
104
106
  bug_tracker_uri: https://github.com/rails/rails/issues
105
- changelog_uri: https://github.com/rails/rails/blob/v7.1.5/activejob/CHANGELOG.md
106
- documentation_uri: https://api.rubyonrails.org/v7.1.5/
107
+ changelog_uri: https://github.com/rails/rails/blob/v7.2.0.beta1/activejob/CHANGELOG.md
108
+ documentation_uri: https://api.rubyonrails.org/v7.2.0.beta1/
107
109
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
108
- source_code_uri: https://github.com/rails/rails/tree/v7.1.5/activejob
110
+ source_code_uri: https://github.com/rails/rails/tree/v7.2.0.beta1/activejob
109
111
  rubygems_mfa_required: 'true'
110
- post_install_message:
112
+ post_install_message:
111
113
  rdoc_options: []
112
114
  require_paths:
113
115
  - lib
@@ -115,15 +117,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
115
117
  requirements:
116
118
  - - ">="
117
119
  - !ruby/object:Gem::Version
118
- version: 2.7.0
120
+ version: 3.1.0
119
121
  required_rubygems_version: !ruby/object:Gem::Requirement
120
122
  requirements:
121
123
  - - ">="
122
124
  - !ruby/object:Gem::Version
123
125
  version: '0'
124
126
  requirements: []
125
- rubygems_version: 3.5.16
126
- signing_key:
127
+ rubygems_version: 3.5.10
128
+ signing_key:
127
129
  specification_version: 4
128
130
  summary: Job framework with pluggable queues.
129
131
  test_files: []