Skip to content

fix(retry): honor the retryAfter option in the default retry strategy - #5683

Open
codeAnqiang-ma wants to merge 1 commit into
nodejs:mainfrom
codeAnqiang-ma:fix/retry-after-option-ignored
Open

fix(retry): honor the retryAfter option in the default retry strategy#5683
codeAnqiang-ma wants to merge 1 commit into
nodejs:mainfrom
codeAnqiang-ma:fix/retry-after-option-ignored

Conversation

@codeAnqiang-ma

Copy link
Copy Markdown

This relates to...

Fixes #5682

Rationale

retryOptions.retryAfter is documented (RetryHandler.md, RetryAgent.md, and the JSDoc in types/retry-handler.d.ts) as a boolean that controls whether the delay before the next retry is inferred from the Retry-After response header, with a default of true. The option was normalized and stored in the constructor but never read: the default retry strategy always used the header, so retryAfter: false silently had no effect and the server kept controlling the retry delay (up to maxTimeout) instead of the configured exponential backoff.

Changes

  • lib/handler/retry-handler.js: the default retry strategy now destructures retryAfter from retryOptions and skips the Retry-After header when the option is explicitly false. Behavior for the default (true) and for any other value is unchanged.
  • test/retry-handler.js: regression test (fails before the fix, passes after) modeled on the neighboring "Should retry immediately when retry-after is zero" test: a 429 with retry-after: 60 and retryAfter: false must schedule the retry via the exponential backoff (500ms), not the header (60s).

Features

N/A

Bug Fixes

  • retryOptions.retryAfter: false now disables Retry-After-based delay inference as documented, affecting RetryHandler, RetryAgent, and interceptors.retry().

Breaking Changes and Deprecations

N/A — only the documented-but-inert retryAfter: false path changes behavior.

Status

  • I have read and agreed to the Developer's Certificate of Origin
  • Tested
  • [S] Benchmarked (optional)
  • Documented (existing docs already describe this behavior; no doc change needed)
  • Review ready
  • In review
  • Merge ready

Test evidence (Node v22.22.3, macOS):

$ node --test test/retry-handler.js
# tests 22
# pass 22
# fail 0

$ node --test test/retry-handler2.js test/retry-agent.js test/retry-handler-controller-proxy.js test/client-retry-resume-backpressure.js test/interceptors/retry.js
# tests 45
# pass 45
# fail 0

npm run lint passes. Not run: the full test suite (only retry-related files, listed above).

Repro from #5682 before/after the fix: fails after ~10s on main (delay taken from Retry-After: 10), fails after ~360ms with this patch (exponential backoff with minTimeout: 100), as expected for retryAfter: false.

Disclosure: this fix was prepared with AI assistance; I reproduced the bug locally and reviewed every change. Signed off per the DCO.

The retryAfter option is documented as a boolean that controls whether
the delay before the next retry is inferred from the Retry-After
response header. It was stored in the handler options but never read:
the default retry strategy always used the Retry-After header, so
setting retryAfter: false had no effect and the server kept controlling
the retry delay instead of the configured exponential backoff.

Signed-off-by: codeAnqiang-ma <273298913+codeAnqiang-ma@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

@mcollina mcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RetryHandler: retryOptions.retryAfter: false is ignored — retry delay still follows the Retry-After header

2 participants