crates/services/src/broadcast/subscriber.rs computed the wait between failed subscribe attempts as 1 << retry_count.max(6) seconds. max(6) acts as a floor rather than a cap, so:
the first retry waited 64 s instead of 1 s;
each later retry doubled with no upper bound (128 s, 256 s, ...);
after enough failures the shift overflows.
A 3-node cluster rehearsal (PostgreSQL + NATS) hit this when NATS dropped out.
Change
New subscribe_retry_delay(retry_count): 1 s, 2 s, 4 s ... capped at 64 s (1u64 << retry_count.min(6)).
retry_count is a u32 and uses saturating_add.
Tests
cargo test -p services --lib subscribe_retry: new unit test subscribe_retry_backoff_grows_then_caps checks the schedule [1, 2, 4, 8, 16, 32, 64, 64, 64, 64] and u32::MAX → 64 s. Passes.
## Problem
`crates/services/src/broadcast/subscriber.rs` computed the wait between failed subscribe attempts as `1 << retry_count.max(6)` seconds. `max(6)` acts as a floor rather than a cap, so:
- the first retry waited 64 s instead of 1 s;
- each later retry doubled with no upper bound (128 s, 256 s, ...);
- after enough failures the shift overflows.
A 3-node cluster rehearsal (PostgreSQL + NATS) hit this when NATS dropped out.
## Change
- New `subscribe_retry_delay(retry_count)`: 1 s, 2 s, 4 s ... capped at 64 s (`1u64 << retry_count.min(6)`).
- `retry_count` is a `u32` and uses `saturating_add`.
## Tests
- `cargo test -p services --lib subscribe_retry`: new unit test `subscribe_retry_backoff_grows_then_caps` checks the schedule `[1, 2, 4, 8, 16, 32, 64, 64, 64, 64]` and `u32::MAX` → 64 s. Passes.
The broadcast subscriber waited 1 << retry_count.max(6) seconds between
failed subscribe attempts. max(6) turns the cap into a floor: the first
retry waited 64 s instead of 1 s, and each later one doubled without a
bound (and would overflow the shift after enough failures).
The delay now comes from subscribe_retry_delay(), 1 s, 2 s, 4 s ... capped
at 64 s, and the retry counter saturates. A unit test pins the schedule
and the top of the range.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
crates/services/src/broadcast/subscriber.rscomputed the wait between failed subscribe attempts as1 << retry_count.max(6)seconds.max(6)acts as a floor rather than a cap, so:A 3-node cluster rehearsal (PostgreSQL + NATS) hit this when NATS dropped out.
Change
subscribe_retry_delay(retry_count): 1 s, 2 s, 4 s ... capped at 64 s (1u64 << retry_count.min(6)).retry_countis au32and usessaturating_add.Tests
cargo test -p services --lib subscribe_retry: new unit testsubscribe_retry_backoff_grows_then_capschecks the schedule[1, 2, 4, 8, 16, 32, 64, 64, 64, 64]andu32::MAX→ 64 s. Passes.