Skip to content

Commit 2731a42

Browse files
authored
Correct retry_intervals exponential backoff documentation (#1014)
The exponential_backoff? docstring claimed retries stop ("before giving up") after the last configured interval. They do not: once the intervals are exhausted, get_interval keeps returning the last interval, so the message is retried indefinitely at that cadence. SQS's redrive policy (maxReceiveCount) is what actually moves an exhausted message to a dead-letter queue. Corrected the docstring to describe the real behavior and added a spec pinning that far-later attempts keep reusing the last interval, so the docs and behavior stay in sync. Signed-off-by: Maciej Mensfeld <maciej@mensfeld.pl>
1 parent 8cd8f5e commit 2731a42

3 files changed

Lines changed: 22 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
## [Unreleased]
22

3+
- Docs: Correct the `retry_intervals` exponential backoff documentation (mensfeld)
4+
- The `exponential_backoff?` docstring claimed retries stop ("before giving up") after the last configured
5+
interval. They do not: once the intervals are exhausted, the last interval is reused for every later
6+
attempt, and SQS's redrive policy (maxReceiveCount) is what ultimately moves a message to a dead-letter queue
7+
- Added a spec pinning that far-later attempts keep reusing the last interval
8+
39
- Fix: `CurrentAttributes.persist` no longer drops a class when called once per class (mensfeld)
410
- The storage key was derived from the per-call index, so registering classes across separate `persist`
511
calls made the third call reuse `cattr_0` and silently overwrite the second class - its attributes were
612
then never serialized or restored
713
- The key now uses the running registry size, so incremental and single-call registration both yield
814
distinct, stable keys (single-call `persist(A, B, C)` keys are unchanged)
15+
916
- Fix: Busy-processor accounting no longer breaks when processor completion raises (mensfeld)
1017
- `Manager#assign` chained `.then { processor_done }.rescue { processor_done }`, so an exception inside
1118
`processor_done` (SQS lookups or a polling strategy's `message_processed` callback) ran completion twice

lib/shoryuken/worker.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,11 @@ def auto_visibility_timeout?
224224
#
225225
# @example Configuring exponential backoff
226226
# shoryuken_options retry_intervals: [1, 5, 25, 125, 625]
227-
# # Will retry after 1s, 5s, 25s, 125s, then 625s before giving up
227+
# # Retries after 1s, 5s, 25s, 125s, then 625s for every later attempt.
228+
# # Shoryuken does not stop retrying on its own once the intervals are
229+
# # exhausted - it keeps reusing the last interval. Configure an SQS
230+
# # redrive policy (maxReceiveCount) to send exhausted messages to a
231+
# # dead-letter queue.
228232
#
229233
# @see #shoryuken_options Documentation for configuring retry_intervals
230234
def exponential_backoff?

spec/lib/shoryuken/middleware/server/exponential_backoff_retry_spec.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,16 @@
9292

9393
expect { subject.call(TestWorker.new, queue, sqs_msg, sqs_msg.body) { raise 'failed' } }.not_to raise_error
9494
end
95+
96+
it 'keeps reusing the last interval for far-later attempts (does not give up)' do
97+
TestWorker.get_shoryuken_options['retry_intervals'] = [300, 1800]
98+
99+
allow(sqs_msg).to receive(:attributes) { { 'ApproximateReceiveCount' => 10 } }
100+
allow(sqs_msg).to receive(:queue) { sqs_queue }
101+
expect(sqs_msg).to receive(:change_visibility).with(visibility_timeout: 1800)
102+
103+
expect { subject.call(TestWorker.new, queue, sqs_msg, sqs_msg.body) { raise 'failed' } }.not_to raise_error
104+
end
95105
end
96106

97107
context 'and the exception is non-retryable' do

0 commit comments

Comments
 (0)