Skip to content

Commit 36c6545

Browse files
committed
fix(playmatch): pace requests strictly at 4 req/s with no burst
1 parent 6f84cfe commit 36c6545

1 file changed

Lines changed: 8 additions & 7 deletions

File tree

src/abstraction/playmatch_client.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@ use uuid::Uuid;
2020

2121
type Limiter = RateLimiter<NotKeyed, InMemoryState, DefaultClock>;
2222

23-
/// Thin newtype wrapper that gates every outbound playmatch request through a shared
24-
/// token bucket sized to playmatch's own server-side limit (4 req/s replenish, 20 burst).
25-
/// On 429 or 5xx it retries with exponential backoff (250 ms, 500 ms, 1 s, 2 s, 4 s).
26-
/// 429s happen when the server's bucket is colder than ours (e.g. shared IP, fresh boot
27-
/// after a previous burst). 5xx errors are treated as transient too.
23+
/// Thin newtype wrapper that paces every outbound playmatch request at one per 250 ms,
24+
/// matching the server's `milliseconds_per_request(250)` exactly. No burst: the local
25+
/// bucket holds at most one token, so two requests can never fire closer together than
26+
/// the server's refill interval. The retry layer (429 or 5xx with exponential backoff:
27+
/// 250 ms, 500 ms, 1 s, 2 s, 4 s) stays as a defence in depth for transient
28+
/// server-side blips.
2829
pub struct PlaymatchClient {
2930
inner: Inner,
3031
limiter: Limiter,
@@ -34,8 +35,8 @@ const MAX_RETRIES: u32 = 5;
3435

3536
impl PlaymatchClient {
3637
pub fn new(inner: Inner) -> Self {
37-
let quota = Quota::per_second(NonZeroU32::new(4).unwrap())
38-
.allow_burst(NonZeroU32::new(20).unwrap());
38+
let quota =
39+
Quota::per_second(NonZeroU32::new(4).unwrap()).allow_burst(NonZeroU32::new(1).unwrap());
3940
Self {
4041
inner,
4142
limiter: RateLimiter::direct(quota),

0 commit comments

Comments
 (0)