activejob 7.1.0.beta1 → 7.1.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c483058510bace1163414149c1aff4177dd5dc026414417a99f240128686ccc6
4
- data.tar.gz: 27f14766eafe75eb955ebae328ef1c154c3bd3aa42251403e6ced8a61f8dc3d1
3
+ metadata.gz: d95076eb165c16b44e30c4f98c72bce402b3124c5754e76ad6b86f1e4e02b81e
4
+ data.tar.gz: e9f4bb0bd99471a34abd21723776a66913b593c605dcd8f84079c029f74cfbc7
5
5
  SHA512:
6
- metadata.gz: eeb8e50e581068b1e9862917d02d99bc8988fc254475e4a70a4a7e231ccb61340dfa276be6d39d0f6ebd4f347a00019d3c3703c946549bb4788dcdd83b46ccc9
7
- data.tar.gz: 23cb3701834db4e4b6ba5adbd77966a50bd0debf8aed7a75d9a83f04355895aad870baca894d6e32183757b9a4a7f62c79748a638f99928be4c497d633302cb5
6
+ metadata.gz: 70fc9872437f7ebb6161686b3b4ed66acd79e8d1b3e750f84384f1818ea213c0a1b038a9b435cc6c727790eb2334d7ea2458810e90b321485b25dec6c6c3d944
7
+ data.tar.gz: ea5ae1a2c0ae70db9c44935f7da32344fd84519de9e7b570815f7194e0b780a6c9aba811128a8740fbefac252e2844760bf7c6aec62653fc84dc86f24fdf8adb
data/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
1
+ ## Rails 7.1.0.rc2 (October 01, 2023) ##
2
+
3
+ * Make sure `scheduled_at` is a Time object when asserting enqueued jobs.
4
+
5
+ *Rafael Mendonça França*
6
+
7
+
8
+ ## Rails 7.1.0.rc1 (September 27, 2023) ##
9
+
10
+ * Set `scheduled_at` attribute as a Time object instead of epoch seconds, and serialize and deserialize the value
11
+ when enqueued. Assigning a numeric/epoch value to scheduled_at= is deprecated; use a Time object instead.
12
+
13
+ Deserializes `enqueued_at` as a Time instead of ISO8601 String.
14
+
15
+ *Ben Sheldon*
16
+
17
+ * Clarify the backoff strategy for the recommended `:wait` option when retrying jobs
18
+
19
+ `wait: :exponentially_longer` is waiting polynomially longer, so it is now recommended to use `wait: :polynomially_longer` to keep the same behavior.
20
+
21
+ *Victor Mours*
22
+
23
+
1
24
  ## Rails 7.1.0.beta1 (September 13, 2023) ##
2
25
 
3
26
  * Fix Active Job log message to correctly report a job failed to enqueue
@@ -12,8 +12,10 @@ module ActiveJob
12
12
  attr_accessor :arguments
13
13
  attr_writer :serialized_arguments
14
14
 
15
- # Timestamp when the job should be performed
16
- attr_accessor :scheduled_at
15
+ # Time when the job should be performed
16
+ attr_reader :scheduled_at
17
+
18
+ attr_reader :_scheduled_at_time # :nodoc:
17
19
 
18
20
  # Job Identifier
19
21
  attr_accessor :job_id
@@ -94,6 +96,8 @@ module ActiveJob
94
96
  @arguments = arguments
95
97
  @job_id = SecureRandom.uuid
96
98
  @queue_name = self.class.queue_name
99
+ @scheduled_at = nil
100
+ @_scheduled_at_time = nil
97
101
  @priority = self.class.priority
98
102
  @executions = 0
99
103
  @exception_executions = {}
@@ -115,7 +119,8 @@ module ActiveJob
115
119
  "exception_executions" => exception_executions,
116
120
  "locale" => I18n.locale.to_s,
117
121
  "timezone" => timezone,
118
- "enqueued_at" => Time.now.utc.iso8601(9)
122
+ "enqueued_at" => Time.now.utc.iso8601(9),
123
+ "scheduled_at" => _scheduled_at_time ? _scheduled_at_time.utc.iso8601(9) : nil,
119
124
  }
120
125
  end
121
126
 
@@ -155,19 +160,32 @@ module ActiveJob
155
160
  self.exception_executions = job_data["exception_executions"]
156
161
  self.locale = job_data["locale"] || I18n.locale.to_s
157
162
  self.timezone = job_data["timezone"] || Time.zone&.name
158
- self.enqueued_at = job_data["enqueued_at"]
163
+ self.enqueued_at = Time.iso8601(job_data["enqueued_at"]) if job_data["enqueued_at"]
164
+ self.scheduled_at = Time.iso8601(job_data["scheduled_at"]) if job_data["scheduled_at"]
159
165
  end
160
166
 
161
167
  # Configures the job with the given options.
162
168
  def set(options = {}) # :nodoc:
163
- self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait]
164
- self.scheduled_at = options[:wait_until].to_f if options[:wait_until]
169
+ self.scheduled_at = options[:wait].seconds.from_now if options[:wait]
170
+ self.scheduled_at = options[:wait_until] if options[:wait_until]
165
171
  self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue]
166
172
  self.priority = options[:priority].to_i if options[:priority]
167
173
 
168
174
  self
169
175
  end
170
176
 
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
+
171
189
  private
172
190
  def serialize_arguments_if_needed(arguments)
173
191
  if arguments_serialized?
@@ -23,7 +23,7 @@ module ActiveJob
23
23
  adapter_jobs.each do |job|
24
24
  job.successfully_enqueued = false
25
25
  if job.scheduled_at
26
- queue_adapter.enqueue_at(job, job.scheduled_at)
26
+ queue_adapter.enqueue_at(job, job._scheduled_at_time.to_f)
27
27
  else
28
28
  queue_adapter.enqueue(job)
29
29
  end
@@ -92,7 +92,7 @@ module ActiveJob
92
92
 
93
93
  run_callbacks :enqueue do
94
94
  if scheduled_at
95
- queue_adapter.enqueue_at self, scheduled_at
95
+ queue_adapter.enqueue_at self, _scheduled_at_time.to_f
96
96
  else
97
97
  queue_adapter.enqueue self
98
98
  end
@@ -21,10 +21,13 @@ 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
25
+ # which <tt>exception.is_a?(klass)</tt> holds true is the one invoked, if any.
26
+ #
24
27
  # ==== Options
25
28
  # * <tt>:wait</tt> - Re-enqueues the job with a delay specified either in seconds (default: 3 seconds),
26
29
  # as a computing proc that takes the number of executions so far as an argument, or as a symbol reference of
27
- # <tt>:exponentially_longer</tt>, which applies the wait algorithm of <tt>((executions**4) + (Kernel.rand * (executions**4) * jitter)) + 2</tt>
30
+ # <tt>:polynomially_longer</tt>, which applies the wait algorithm of <tt>((executions**4) + (Kernel.rand * (executions**4) * jitter)) + 2</tt>
28
31
  # (first wait ~3s, then ~18s, then ~83s, etc)
29
32
  # * <tt>:attempts</tt> - Re-enqueues the job the specified number of times (default: 5 attempts) or a symbol reference of <tt>:unlimited</tt>
30
33
  # to retry the job until it succeeds
@@ -40,11 +43,11 @@ module ActiveJob
40
43
  # retry_on CustomInfrastructureException, wait: 5.minutes, attempts: :unlimited
41
44
  #
42
45
  # retry_on ActiveRecord::Deadlocked, wait: 5.seconds, attempts: 3
43
- # retry_on Net::OpenTimeout, Timeout::Error, wait: :exponentially_longer, attempts: 10 # retries at most 10 times for Net::OpenTimeout and Timeout::Error combined
46
+ # retry_on Net::OpenTimeout, Timeout::Error, wait: :polynomially_longer, attempts: 10 # retries at most 10 times for Net::OpenTimeout and Timeout::Error combined
44
47
  # # To retry at most 10 times for each individual exception:
45
- # # retry_on Net::OpenTimeout, wait: :exponentially_longer, attempts: 10
48
+ # # retry_on Net::OpenTimeout, wait: :polynomially_longer, attempts: 10
46
49
  # # retry_on Net::ReadTimeout, wait: 5.seconds, jitter: 0.30, attempts: 10
47
- # # retry_on Timeout::Error, wait: :exponentially_longer, attempts: 10
50
+ # # retry_on Timeout::Error, wait: :polynomially_longer, attempts: 10
48
51
  #
49
52
  # retry_on(YetAnotherCustomAppException) do |job, error|
50
53
  # ExceptionNotifier.caught(error)
@@ -57,6 +60,12 @@ module ActiveJob
57
60
  # end
58
61
  # end
59
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
60
69
  rescue_from(*exceptions) do |error|
61
70
  executions = executions_for(exceptions)
62
71
  if attempts == :unlimited || executions < attempts
@@ -81,6 +90,9 @@ module ActiveJob
81
90
  #
82
91
  # 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.
83
92
  #
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
94
+ # which <tt>exception.is_a?(klass)</tt> holds true is the one invoked, if any.
95
+ #
84
96
  # ==== Example
85
97
  #
86
98
  # class SearchIndexingJob < ActiveJob::Base
@@ -156,7 +168,8 @@ module ActiveJob
156
168
  jitter = jitter == JITTER_DEFAULT ? self.class.retry_jitter : (jitter || 0.0)
157
169
 
158
170
  case seconds_or_duration_or_algorithm
159
- when :exponentially_longer
171
+ when :exponentially_longer, :polynomially_longer
172
+ # This delay uses a polynomial backoff strategy, which was previously misnamed as exponential
160
173
  delay = executions**4
161
174
  delay_jitter = determine_jitter_for_delay(delay, jitter)
162
175
  delay + delay_jitter + 2
@@ -10,7 +10,7 @@ module ActiveJob
10
10
  MAJOR = 7
11
11
  MINOR = 1
12
12
  TINY = 0
13
- PRE = "beta1"
13
+ PRE = "rc2"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -76,7 +76,7 @@ module ActiveJob
76
76
  def perform_start(event)
77
77
  info do
78
78
  job = event.payload[:job]
79
- "Performing #{job.class.name} (Job ID: #{job.job_id}) from #{queue_name(event)} enqueued at #{job.enqueued_at}" + args_info(job)
79
+ "Performing #{job.class.name} (Job ID: #{job.job_id}) from #{queue_name(event)} enqueued at #{job.enqueued_at.utc.iso8601(9)}" + args_info(job)
80
80
  end
81
81
  end
82
82
  subscribe_log_level :perform_start, :info
@@ -54,7 +54,7 @@ module ActiveJob
54
54
  "wrapped" => job_class,
55
55
  "queue" => queue,
56
56
  "args" => scheduled_jobs.map { |job| [job.serialize] },
57
- "at" => scheduled_jobs.map { |job| job.scheduled_at }
57
+ "at" => scheduled_jobs.map { |job| job.scheduled_at&.to_f }
58
58
  )
59
59
  enqueued_count += jids.compact.size
60
60
  end
@@ -59,7 +59,7 @@ module ActiveJob
59
59
  end
60
60
 
61
61
  def filtered_time?(job)
62
- job.scheduled_at > at.to_f if at && job.scheduled_at
62
+ job.scheduled_at > at if at && job.scheduled_at
63
63
  end
64
64
 
65
65
  def filtered_queue?(job)
@@ -730,7 +730,7 @@ module ActiveJob
730
730
 
731
731
  def instantiate_job(payload, skip_deserialize_arguments: false)
732
732
  job = payload[:job].deserialize(payload)
733
- job.scheduled_at = payload[:at].to_f if payload.key?(:at)
733
+ job.scheduled_at = Time.at(payload[:at]) if payload.key?(:at)
734
734
  job.send(:deserialize_arguments_if_needed) unless skip_deserialize_arguments
735
735
  job
736
736
  end
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.0.beta1
4
+ version: 7.1.0.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-13 00:00:00.000000000 Z
11
+ date: 2023-10-01 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.0.beta1
19
+ version: 7.1.0.rc2
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.0.beta1
26
+ version: 7.1.0.rc2
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: globalid
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -102,10 +102,10 @@ licenses:
102
102
  - MIT
103
103
  metadata:
104
104
  bug_tracker_uri: https://github.com/rails/rails/issues
105
- changelog_uri: https://github.com/rails/rails/blob/v7.1.0.beta1/activejob/CHANGELOG.md
106
- documentation_uri: https://api.rubyonrails.org/v7.1.0.beta1/
105
+ changelog_uri: https://github.com/rails/rails/blob/v7.1.0.rc2/activejob/CHANGELOG.md
106
+ documentation_uri: https://api.rubyonrails.org/v7.1.0.rc2/
107
107
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
108
- source_code_uri: https://github.com/rails/rails/tree/v7.1.0.beta1/activejob
108
+ source_code_uri: https://github.com/rails/rails/tree/v7.1.0.rc2/activejob
109
109
  rubygems_mfa_required: 'true'
110
110
  post_install_message:
111
111
  rdoc_options: []