fix(proxy): flush virtual-key model_max budget spend to Redis after success logging - #27334
Conversation
…logging. _PROXY_VirtualKeyModelMaxBudgetLimiter subclasses RouterBudgetLimiting but does not run its __init__, so the periodic Redis sync task never starts and spend stayed in memory. Push the increment pipeline when Redis is configured so multi-worker enforcement and cache keys stay consistent. Co-authored-by: Cursor <cursoragent@cursor.com>
Assert _push_in_memory_increments_to_redis runs after async_log_success_event when dual_cache.redis_cache is set, and is skipped when Redis is not configured. Co-authored-by: Cursor <cursoragent@cursor.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Greptile SummaryThis PR fixes a bug where
Confidence Score: 5/5Safe to merge; the change is a targeted 3-line addition that restores expected multi-worker budget enforcement without altering any existing code paths. The fix directly addresses the documented root cause, is well-tested with two new mock-based unit tests covering both branches, and the underlying flush method already guards against empty queues and uses non-blocking task creation. No existing behavior is altered for deployments without Redis. No files require special attention; both changed files are straightforward.
|
| Filename | Overview |
|---|---|
| litellm/proxy/hooks/model_max_budget_limiter.py | Adds a per-request Redis flush after spend increments in async_log_success_event; correctly targets the root cause (parent init never runs so the periodic task is never scheduled). |
| tests/proxy_unit_tests/test_unit_test_max_model_budget_limiter.py | Two new unit tests cover the Redis-configured and no-Redis branches of the fix; both use proper AsyncMock patching and assert the correct invocation behavior. |
Reviews (1): Last reviewed commit: "Add unit tests for virtual-key model max..." | Re-trigger Greptile
…udget_redis_flush fix(proxy): flush virtual-key model_max budget spend to Redis after success logging
Linear ticket
Resolves LIT-2893
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
tests/proxy_unit_tests/test_unit_test_max_model_budget_limiter.py(same location as the existing model max budget limiter suite). Note: the repo template points attests/test_litellm/; these tests follow the existing pattern for this hook inproxy_unit_tests. If maintainers want a mirror undertests/test_litellm/, I can add one.make test-unit(not run in this environment wheremake/uvis unavailable; locally:pytest tests/proxy_unit_tests/test_unit_test_max_model_budget_limiter.py— 13 passed.)@greptileaiand received a Confidence Score of at least 4/5 before requesting a maintainer reviewCI (LiteLLM team)
Branch creation CI run
Link:
CI run for the last commit
Link:
Merge / cherry-pick CI run
Links:
Screenshots / Proof of Fix
Manual repro (two proxy workers, one Redis):
litellm_settings.cache+ Rediscache_params, andenable_redis_auth_cache: truesouser_api_key_cacheshares the same Redis-backedDualCacheas_PROXY_VirtualKeyModelMaxBudgetLimiter.model_max_budgetset to a very small cap for a model alias (e.g. model group name matching enforcement).budget_exceeded, proving spend visible across workers after the fix.Before the fix: Redis could show budget window metadata (e.g.
virtual_key_budget_start_time:*) whilevirtual_key_spend:*was missing or stale across workers, because increments stayed in the in-memory queue and were never flushed (subclass never runsRouterBudgetLimiting.__init__, so the periodic Redis sync task never starts).After the fix:
async_log_success_eventcalls_push_in_memory_increments_to_redis()whendual_cache.redis_cacheis set, so the increment pipeline runs and multi-worker enforcement matches intent.Type
🐛 Bug Fix
Changes
litellm/proxy/hooks/model_max_budget_limiter.py: After virtual-key and end-user model budget increments inasync_log_success_event,await self._push_in_memory_increments_to_redis()when Redis is attached todual_cache, so queued increments are written with the same mechanism asRouterBudgetLimiting.tests/proxy_unit_tests/test_unit_test_max_model_budget_limiter.py:test_async_log_success_event_pushes_redis_increments_when_redis_configured— asserts_push_in_memory_increments_to_redisis awaited once whenredis_cacheis set.test_async_log_success_event_skips_redis_push_without_redis— asserts it is not awaited when Redis is not configured.