-
released this
2026-08-25 19:09:27 -05:00 | 67 commits to main since this releaseThe live monitor was taking sustained Riot 429s while polling 11 summoners once
every 5 minutes — one call every ~27s, roughly 4% of a personal key's budget. It
was never the heavy spender: the key is shared, and nothing here could see that.Added
- Riot budget telemetry. Every Riot response carries
X-App-Rate-Limit,
X-App-Rate-Limit-Count, the method-scoped pair, and — on a 429 —
X-Rate-Limit-Type. All of it was discarded, leavingRetry-Afteras the only
evidence a 429 had happened, and no way at all to tell an application limit
from a method one.RiotApiClientBasenow reads them and logs a
Riot budget nearly spentwarning once the key-wide count reaches 80% of the
cap, reportingmine(this process's dispatches) besidekey(what Riot
counted for the whole key). The gap between those two is what other holders
of the key spent — the one thing that could not be observed from inside this
process, and the reason a 4%-of-budget poller was seeing 429s at all. RiotRateLimiterLikegained an optionalgetLongWindowCount()so the client
can report its own spend without importing the concrete limiter.
Changed
riotMaxRequestsPer2Min75 → 40. The published personal-key cap is
~100/2min, but the same key is also held by thelol-companionproject, whose
limiter runs to its own ceiling knowing nothing of this one. Two independent
limiters on one budget are safe only if their ceilings sum under the cap —
these summed to 165. 40 here pairs with ~50 there.- Recent-form lookup drops from 5 matches to 3. The enrichment pass cost
10 × (1 + 5) = 60 match calls, and with the ranked pass alongside it a single
detected game spent ~70 requests of a shared 100 in one burst. At 3 the same
pass costs 40. Recent form is a one-line hint, not a sample worth 60 requests.
Fixed
- A 429 no longer manufactures a second 429. The retry wait was
Math.min(retryAfter, 10), so Riot asking for 17s produced a retry at 10s —
while still rate-limited — turning one refused request into two and feeding the
pressure that caused it. Production logs show precisely that at 09:26:02:
retryAfter=17logged as "retrying in 10s", refused again ten seconds later.
The wait now honors what Riot asks for. - A long
Retry-Afterskips the call rather than overrunning the poll cycle.
Simply honoring an app-limitRetry-Afterof up to 120s across 3 retries could
sleep ~6 minutes inside a 5-minute cycle, andpollOnce's in-progress guard
would then drop the next cycle wholesale. Waits beyond 25s now abandon the
call — the last staggered summoner starts ~27s before the cycle is due. A
spectator answer describes right now, so a two-minute-old one is worthless when
the next cycle re-asks in five minutes. - The header-less 429 fallback rose from 2s to 8s. Riot omits
Retry-Afteron
some service-level 429s, and 2s retried straight back into the same wall. js-yamlpinned to^5.4.0viaoverrides, clearing GHSA-5p4m-2wfm-xmqj
(High — quadratic CPU consumption in!!omapresolution), which the
npm audit --audit-level=highCI gate step was failing on. Dev-only,
reached solely via
ts-jest → @jest/transform → babel-plugin-istanbul → @istanbuljs/load-nyc-config,
so it was never in the production image (npm ci --omit=dev). The 3.x line
never received the backport; the major bump is safe becauseload-nyc-config
callsjs-yaml's.load(), not thesafeLoad()removed in 4.x.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- Riot budget telemetry. Every Riot response carries