fix(rate_limit): don't block the executor thread while waiting to retry
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 acurrent_threadruntime and asserts the ticker makes progress while the retry waits.