@@ -20,11 +20,12 @@ use uuid::Uuid;
2020
2121type 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.
2829pub struct PlaymatchClient {
2930 inner : Inner ,
3031 limiter : Limiter ,
@@ -34,8 +35,8 @@ const MAX_RETRIES: u32 = 5;
3435
3536impl 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