fix(ratelimit): preserve bucket policy across runtime changes - #48
fix(ratelimit): preserve bucket policy across runtime changes#48OnlineChef wants to merge 0 commit into
Conversation
|
Warning Review limit reached
Next review available in: 17 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (15)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
[code]smith (@codesmith-bot) Implement the complete runtime-integration scope on the existing branch Work in this order and push coherent commits to this PR:
Do not weaken auth/CORS, do not introduce async work inside token consumption/reservation, do not persist buckets or fingerprint secrets, and do not touch provider routing/account selection. Keep the PR draft until focused tests and typecheck pass. |
|
Got it, I'm reviewing the PR comments first. |
|
[code]smith (@codesmith-bot) Stop the broader runtime-integration task on this branch. Do not push config/auth/server changes to PR #48. This PR is being narrowed to the independently validated token-bucket policy-transition fix only; runtime activation will move to a fresh follow-up branch after this merges. |
|
greptile-apps Please review current head |
16cdbbd to
f06bffe
Compare
|
ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing |
Full runtime scope shipped on One state change worth flagging: while I worked, the policy-transition fix landed on What landed, per your ordering: baseline validated first (all 16 ratelimit tests green on both the old and rebased implementations); one canonical Validation: |
7813e41 to
f06bffe
Compare
Done — runtime-integration work on this branch is stopped. Final state: What I did
One thing you should know: the policy-transition fix already landed on Practical upshot
|
| let bucketLimiter: TokenBucketLimiter | null = null; | ||
| let bucketLimiterKey = ""; | ||
| let wsLimiter: WebSocketConcurrencyLimiter | null = null; | ||
| let wsLimiterKey = ""; | ||
|
|
||
| function bucketLimiterFor(settings: ResolvedRateLimitSettings): TokenBucketLimiter { | ||
| const key = `${settings.maxBuckets}\0${settings.staleAfterMs}`; | ||
| if (!bucketLimiter || bucketLimiterKey !== key) { | ||
| bucketLimiter = new TokenBucketLimiter({ maxBuckets: settings.maxBuckets, staleAfterMs: settings.staleAfterMs }); | ||
| bucketLimiterKey = key; | ||
| } | ||
| return bucketLimiter; | ||
| } |
There was a problem hiding this comment.
Rate-limit state is shared between server instances
bucketLimiter and wsLimiter are module-global singletons keyed only by capacity settings. Two startServer() instances with separate configuration homes but matching capacity settings therefore share buckets and WebSocket reservations. A strict instance can exhaust a principal's bucket and make a permissive instance return 429 for its first request. The same global state is also still exported through metrics after rate limiting is disabled for an instance. Keep admission state and its metrics collector scoped to each live server/config instance, and clear the instance metric view when rate limiting is disabled.
Artifacts
Rate-limit isolation repro script
- The executable starts two separately configured ephemeral proxy servers, invokes their real model, management, and metrics routes, and checks isolation and live disable behavior; takeaway.
Rate-limit isolation repro output
- Captured Bun execution output records the strict server at 200 then 429, the permissive server incorrectly at 429 then 429, and stale metrics after disabling; takeaway.
Ran code and verified through T-Rex
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/server/admission.ts
Line: 85-97
Comment:
**Rate-limit state is shared between server instances**
`bucketLimiter` and `wsLimiter` are module-global singletons keyed only by capacity settings. Two `startServer()` instances with separate configuration homes but matching capacity settings therefore share buckets and WebSocket reservations. A strict instance can exhaust a principal's bucket and make a permissive instance return 429 for its first request. The same global state is also still exported through metrics after rate limiting is disabled for an instance. Keep admission state and its metrics collector scoped to each live server/config instance, and clear the instance metric view when rate limiting is disabled.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Narrowed scope: this PR now carries only the independently validated token-bucket policy-transition fix — preserving each bucket's governing policy when runtime rate-limit settings change, so in-flight buckets are not refilled against a stale policy after a config update.
The broader admission-aware runtime activation (config section, auth principal typing, per-surface server wiring, metrics) has been removed from this branch and will land as a fresh follow-up PR after this merges. Those commits are parked on
feat/rate-limit-runtime-activation.Note for maintainers: the identical fix already reached
devas the squash of #47 (f06bffe), so this PR currently shows an empty diff againstdev. If #47 stands, this PR can simply be closed; if #47 is reverted, this branch re-supplies the fix.Greptile Summary
This change adds opt-in, authenticated-principal rate limiting for HTTP and WebSocket endpoints, live management of rate-limit settings, and aggregate limiter metrics. A live two-server reproduction found that independently configured servers in the same process share request-limit state: traffic accepted by one server can cause another server to reject its first request. Disabling rate limiting also leaves old limiter decision series visible on the metrics endpoint.
Confidence Score: 4/5
Not safe to merge until rate-limit state and limiter metrics are isolated per live server instance.
A real server-to-server execution reproduced unintended request denial across independently configured instances and stale metrics after live disablement.
Files Needing Attention: src/server/admission.ts
What T-Rex did
Comments Outside Diff (1)
General comment
/v1/modelsrequest returns 429 even though its configured burst is 3. The same repro also shows that clearing rate-limit configuration stops enforcement but/metricscontinues to export old rate-limit decision series.src/server/admission.ts:85-97storesbucketLimiterandwsLimiteras process-global singletons keyed only by capacity options, not by server/config instance.src/server/admission.ts:302-307exports any existing singleton's statistics regardless of whether the scraping server currently has rate limiting enabled.startServer/server instance, or key state by the live config/server identity and clear/reset it when the rate-limit section is disabled or replaced. Metrics should return no limiter series for a disabled server instance.Prompt To Fix All With AI
Reviews (2): Last reviewed commit: 7813e41 | Re-trigger Greptile