Skip to content

Commit 1924d5d

Browse files
committed
Change usage of retry-after header
With this change the retry-after header will be treated as an absolute value and not used for exponential backoff. Whenever the retry-after interval sent by the service broker is larger than the calculated interval using the base interval and exponential backoff, the retry-after interval will be used. When the CC calculated interval is larger the retry-after interval will be ignored.
1 parent 48e9090 commit 1924d5d

File tree

2 files changed

+125
-25
lines changed

2 files changed

+125
-25
lines changed

app/jobs/reoccurring_job.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def maximum_duration_seconds=(duration)
3030
end
3131

3232
def polling_interval_seconds
33-
[@polling_interval || 0, default_polling_interval_seconds].max
33+
@polling_interval || 0
3434
end
3535

3636
def polling_interval_seconds=(interval)
@@ -59,7 +59,7 @@ def default_polling_exponential_backoff
5959
end
6060

6161
def next_execution_in
62-
polling_interval_seconds * (default_polling_exponential_backoff**retry_number)
62+
[polling_interval_seconds, default_polling_interval_seconds * (default_polling_exponential_backoff**retry_number)].max
6363
end
6464

6565
def next_enqueue_would_exceed_maximum_duration?

spec/unit/jobs/reoccurring_job_spec.rb

Lines changed: 123 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,13 @@ def perform
118118
expect(job.polling_interval_seconds).to eq(24.hours)
119119
end
120120

121-
context 'exponential backoff rate' do
122-
context 'updates the polling interval' do
123-
it 'when changing exponential backoff rate only' do
121+
describe 'exponential backoff rate' do
122+
context 'when changing exponential backoff rate only' do
123+
before do
124124
TestConfig.config[:broker_client_async_poll_exponential_backoff_rate] = 2.0
125+
end
125126

127+
it 'updates the polling interval' do
126128
enqueued_time = 0
127129

128130
Timecop.freeze do
@@ -141,11 +143,15 @@ def perform
141143
end
142144
end
143145
end
146+
end
144147

145-
it 'when changing exponential backoff rate and default polling interval' do
148+
context 'when changing exponential backoff rate and default polling interval' do
149+
before do
146150
TestConfig.config[:broker_client_async_poll_exponential_backoff_rate] = 1.3
147151
TestConfig.config[:broker_client_default_async_poll_interval_seconds] = 10
152+
end
148153

154+
it 'updates the polling interval' do
149155
enqueued_time = 0
150156

151157
Timecop.freeze do
@@ -164,36 +170,130 @@ def perform
164170
end
165171
end
166172
end
173+
end
167174

168-
it 'when changing exponential backoff rate and retry_after from the job' do
169-
TestConfig.config[:broker_client_async_poll_exponential_backoff_rate] = 1.3
170-
TestConfig.config[:broker_client_default_async_poll_interval_seconds] = 10
175+
describe 'changing exponential backoff rate and retry_after from the job' do
176+
context 'when retry-after is larger than calculated backoff' do
177+
let(:fake_job) { FakeJob.new(retry_after: [20, 30]) }
171178

172-
enqueued_time = 0
179+
before do
180+
TestConfig.config[:broker_client_async_poll_exponential_backoff_rate] = 1.3
181+
TestConfig.config[:broker_client_default_async_poll_interval_seconds] = 10
182+
end
173183

174-
Timecop.freeze do
175-
Jobs::Enqueuer.new(queue: Jobs::Queues.generic).enqueue_pollable(FakeJob.new(retry_after: [20, 30]))
176-
execute_all_jobs(expected_successes: 1, expected_failures: 0)
177-
enqueued_time = Time.now
184+
it 'uses retry-after interval' do
185+
enqueued_time = 0
186+
187+
Timecop.freeze do
188+
Jobs::Enqueuer.new(queue: Jobs::Queues.generic).enqueue_pollable(fake_job)
189+
execute_all_jobs(expected_successes: 1, expected_failures: 0)
190+
enqueued_time = Time.now
191+
end
192+
193+
# the job should run after 20s (20s > 10 * 1.3^0)
194+
Timecop.freeze(19.seconds.after(enqueued_time)) do
195+
execute_all_jobs(expected_successes: 0, expected_failures: 0)
196+
end
197+
198+
Timecop.freeze(21.seconds.after(enqueued_time)) do
199+
enqueued_time = Time.now
200+
execute_all_jobs(expected_successes: 1, expected_failures: 0)
201+
end
202+
203+
# the job should run after 30s (30s > 10 * 1.3^1)
204+
Timecop.freeze(29.seconds.after(enqueued_time)) do
205+
execute_all_jobs(expected_successes: 0, expected_failures: 0)
206+
end
207+
208+
Timecop.freeze(31.seconds.after(enqueued_time)) do
209+
execute_all_jobs(expected_successes: 1, expected_failures: 0)
210+
end
178211
end
212+
end
179213

180-
# the job should run after 20s * 1.3^0 = 20 seconds
181-
Timecop.freeze(19.seconds.after(enqueued_time)) do
182-
execute_all_jobs(expected_successes: 0, expected_failures: 0)
214+
context 'when retry-after is smaller than calculated backoff' do
215+
let(:fake_job) { FakeJob.new(retry_after: [10, 20]) }
216+
217+
before do
218+
TestConfig.config[:broker_client_async_poll_exponential_backoff_rate] = 1.3
219+
TestConfig.config[:broker_client_default_async_poll_interval_seconds] = 30
183220
end
184221

185-
Timecop.freeze(21.seconds.after(enqueued_time)) do
186-
enqueued_time = Time.now
187-
execute_all_jobs(expected_successes: 1, expected_failures: 0)
222+
it 'uses calculated interval' do
223+
enqueued_time = 0
224+
225+
Timecop.freeze do
226+
Jobs::Enqueuer.new(queue: Jobs::Queues.generic).enqueue_pollable(fake_job)
227+
execute_all_jobs(expected_successes: 1, expected_failures: 0)
228+
enqueued_time = Time.now
229+
end
230+
231+
# the job should run after 30s (30s > 10s)
232+
Timecop.freeze(29.seconds.after(enqueued_time)) do
233+
execute_all_jobs(expected_successes: 0, expected_failures: 0)
234+
end
235+
236+
Timecop.freeze(31.seconds.after(enqueued_time)) do
237+
enqueued_time = Time.now
238+
execute_all_jobs(expected_successes: 1, expected_failures: 0)
239+
end
240+
241+
# the job should run after 30s (30s * 1.3^1 = 39 > 20s)
242+
Timecop.freeze(38.seconds.after(enqueued_time)) do
243+
execute_all_jobs(expected_successes: 0, expected_failures: 0)
244+
end
245+
246+
Timecop.freeze(40.seconds.after(enqueued_time)) do
247+
execute_all_jobs(expected_successes: 1, expected_failures: 0)
248+
end
188249
end
250+
end
189251

190-
# the job should run after 30s * 1.3^1 = 39 seconds
191-
Timecop.freeze(38.seconds.after(enqueued_time)) do
192-
execute_all_jobs(expected_successes: 0, expected_failures: 0)
252+
context 'when calculated backoff gets larger than retry-after' do
253+
let(:fake_job) { FakeJob.new(retry_after: [15, 15, 15]) }
254+
255+
before do
256+
TestConfig.config[:broker_client_async_poll_exponential_backoff_rate] = 2
257+
TestConfig.config[:broker_client_default_async_poll_interval_seconds] = 5
193258
end
194259

195-
Timecop.freeze(40.seconds.after(enqueued_time)) do
196-
execute_all_jobs(expected_successes: 1, expected_failures: 0)
260+
it 'uses retry-after until calculated backoff is larger' do
261+
enqueued_time = 0
262+
263+
Timecop.freeze do
264+
Jobs::Enqueuer.new(queue: Jobs::Queues.generic).enqueue_pollable(fake_job)
265+
execute_all_jobs(expected_successes: 1, expected_failures: 0)
266+
enqueued_time = Time.now
267+
end
268+
269+
# the job should run after 15s (15s > 5s (5 * 2^0))
270+
Timecop.freeze(14.seconds.after(enqueued_time)) do
271+
execute_all_jobs(expected_successes: 0, expected_failures: 0)
272+
end
273+
274+
Timecop.freeze(16.seconds.after(enqueued_time)) do
275+
enqueued_time = Time.now
276+
execute_all_jobs(expected_successes: 1, expected_failures: 0)
277+
end
278+
279+
# the job should run after 15s (15s > 10s (5 * 2^1))
280+
Timecop.freeze(14.seconds.after(enqueued_time)) do
281+
execute_all_jobs(expected_successes: 0, expected_failures: 0)
282+
end
283+
284+
Timecop.freeze(16.seconds.after(enqueued_time)) do
285+
enqueued_time = Time.now
286+
execute_all_jobs(expected_successes: 1, expected_failures: 0)
287+
end
288+
289+
# the job should run after 20s (20s > 15s (5 * 2^2))
290+
Timecop.freeze(19.seconds.after(enqueued_time)) do
291+
execute_all_jobs(expected_successes: 0, expected_failures: 0)
292+
end
293+
294+
Timecop.freeze(21.seconds.after(enqueued_time)) do
295+
execute_all_jobs(expected_successes: 1, expected_failures: 0)
296+
end
197297
end
198298
end
199299
end

0 commit comments

Comments
 (0)