activejob 7.1.0.beta1 → 7.1.0.rc2

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: 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: []