Fix: Reducing 429 errors due to RPM limits reached through dynamic delay - #566
Open
ShubhanC wants to merge 12 commits into
Open
Fix: Reducing 429 errors due to RPM limits reached through dynamic delay#566ShubhanC wants to merge 12 commits into
ShubhanC wants to merge 12 commits into
Conversation
Apply per-model RPM/TPM delays after route resolution so the throttler sees the actual resolved model, not the client-sent model name. - New throttler service (services/throttler.ts) that reads model rate limits from the DB, checks live usage via ratelimit service, and applies delays when usage exceeds a configurable threshold. - Per-provider delay thresholds in config/provider-limits.json and services/provider-limits.ts. - applyThrottle() calls in proxy, anthropic, and responses dispatch functions — right before the upstream provider call. - Dockerfile copies server/config into the runtime image. - Fix time-boundary flake in analytics-requests.test.ts (hardcoded dates now relative to Date.now()). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
synced with main freellmapi
ShubhanC
force-pushed
the
throttler-branch
branch
from
July 27, 2026 00:50
e91343b to
4b30258
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
When using agentic tools alongside freellmapi, we often run into an issue of reaching Requests per Minute (RPM) limits very quickly, due to repeated requests being sent rapidly. This PR implements a per-model rate limiter delay feature that applies request delays when usage exceeds provider thresholds. The throttler runs AFTER route resolution, so it sees the actual resolved model (not the client-sent model name), enabling accurate per-model rate limit enforcement.
The feature works by:
-- For example: Gemma4 26B from Google AI Studio has a max RPM of 10 and TPM of, so the delay will start kicking in once you reach 5 RPM requests.
Testing:
The 2 test failures in
analytics-requests.test.tsare pre-existing and unrelated to this PR (confirmed by running the same test onmainbranch, which fails identically).Fixes
New Throttler Service (
services/throttler.ts)Implements per-model request throttling with the following features:
Delay Formula:
delay = max(100ms, floor((ratio - threshold) * 20000))whereratio = used/limitDual-axis enforcement: Takes the MAX of RPM and TPM delays to ensure both axes are respected
Per-provider thresholds: Reads from
server/config/provider-limits.json(defaults to 0.5 for known providers, 0.8 for unknown)Graceful degradation: Returns 0 delay if model has no DB record, if rate limit status is unavailable, or if DB throws
Logging: Every request logs either "pass" (below threshold) or "delay" (above threshold) with full context:
Integration Points
The throttler is called from the dispatch function in each route handler, right before the upstream provider call:
routes/proxy.ts— POST/v1/chat/completions, POST/v1/completionsroutes/responses.ts— POST/v1/responsesroutes/anthropic.ts— POST/v1/messagesThis ordering ensures the throttler sees the resolved model, not the client-sent model name — critical for auto-routed requests where the client sends
model: "auto".Tests
Unit Tests (
services/throttler.test.ts) — 17 testscalculateDelay: boundary conditions, proportional delays, null limits, max of RPM/TPMcheckThrottle: DB handling, logging, threshold variations (0.5, 0.8, 1.0, 0.99)applyThrottle: timing behavior with fake timersIntegration Tests (
routes/throttler-integration.test.ts) — 8 testsLoad Tests (
services/throttler-load.test.ts) — 4 testsPerformance Impact
While tracking quantitative change has been difficult to measure, the throttler transforms what would be hard failures (429 Too Many Requests) into managed delays that allow all requests to eventually succeed. I have some days where my success to failure ratio is 20:1, while most days are closer to 2:1 or 3:1. Before, most days with this tool had a ratio of 1:1, even with removal of bad keys and endpoints.
Found While Testing (Pre-existing, NOT fixed here)
analytics-requests.test.ts— Date boundary issueTwo tests in
analytics-requests.test.tsfail with hardcoded dates from July 6, 2026:Root cause: The test inserts data with
created_at = '2026-07-06'but the query calculatessince = now - 7 days. On July 14, 2026, this puts the cutoff at July 7 — so July 6 data is excluded by the WHERE clause.Verified: The same 2 tests fail identically on
mainbranch (1022 passed on main, including these failing).This is a pre-existing test bug, not introduced by this PR.
Full Suite Results
All 29 throttler-specific tests pass. The 2 failures are pre-existing and unrelated to this PR.
Partially generated with Claude Code