Skip to content

fix(rate_limit): don't block the executor thread while waiting to retry - #130

Merged
AntoniosBarotsis merged 1 commit into
resend:mainfrom
pcbeingused333:fix/async-retry-sleep
Nov 14, 2026
Merged

AntoniosBarotsis merged 1 commit into
resend:mainfrom
pcbeingused333:fix/async-retry-sleep

Conversation

@pcbeingused333

@pcbeingused333 pcbeingused333 commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

send_with_retry_opts (and retry! / retry_opts!) waited between retries with std::thread::sleep inside an async fn. On a single-threaded runtime (or whenever worker threads are saturated) that stalls every other task for the whole backoff, which is at least 1 s by default and ratelimit_reset seconds when the API sends it.

Fix. Wait with futures_timer::Delay, which is runtime-agnostic (the crate does not depend on tokio outside dev-dependencies) and is already in the dependency tree through governor. Added a CHANGELOG entry under Unreleased.

Test. rate_limit::test::test_retry_does_not_block_executor runs the retry next to a ticker task on a current_thread runtime and asserts the ticker made progress before the retry fired (red before: the ticker never ran during the sleep).

Reproduction

retry_opts! on a call that returns Error::RateLimit, joined with any other task on #[tokio::main(flavor = "current_thread")]: the other task does not run until the backoff ends.


This PR was prepared with the assistance of an AI tool (Claude Code).


Summary by cubic

Stops send_with_retry_opts (and the retry!/retry_opts! macros) from blocking the executor thread between retries. Previously the backoff used std::thread::sleep in an async context, which stalled every other task on single-threaded runtimes for the full wait duration. It now awaits futures_timer::Delay instead, which is runtime-agnostic and already in the dependency tree via governor.

Tests

  • Adds test_retry_does_not_block_executor, which runs a retry alongside a ticker task on a current_thread runtime and asserts the ticker makes progress while the retry waits.

Written for commit 63d6385. Summary will update on new commits.

View guided diff

send_with_retry_opts slept with std::thread::sleep inside an async fn, which
stalls every other task on the same runtime thread during a rate-limit backoff.
Use futures_timer::Delay (already in the tree via governor) instead.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@AntoniosBarotsis
AntoniosBarotsis merged commit 34d7b48 into resend:main Nov 14, 2026
1 check passed
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.

2 participants