Skip to content

Commit 460ef37

Browse files
committed
fix
1 parent 5efe59e commit 460ef37

File tree

1 file changed

+52
-2
lines changed

1 file changed

+52
-2
lines changed

litellm/proxy/common_utils/http_parsing_utils.py

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import json
2+
import weakref
23
from typing import Any, Dict, List, Optional
34

45
import orjson
@@ -8,6 +9,10 @@
89
from litellm.proxy._types import ProxyException
910
from litellm.types.router import Deployment
1011

12+
# Use a regular dictionary with manual cleanup
13+
# WeakValueDictionary doesn't work well with our setup since request objects may be kept alive
14+
_request_body_cache: Dict[int, Dict] = {}
15+
1116

1217
async def _read_request_body(request: Optional[Request]) -> Dict:
1318
"""
@@ -90,16 +95,50 @@ async def _read_request_body(request: Optional[Request]) -> Dict:
9095
return {}
9196

9297

98+
def clear_request_cache(request: Optional[Request] = None) -> None:
99+
"""
100+
Clear cached request bodies to free memory.
101+
102+
Parameters:
103+
- request: If provided, only clear cache for this specific request.
104+
If None, clear entire cache.
105+
"""
106+
global _request_body_cache
107+
108+
if request is not None:
109+
request_id = id(request)
110+
if request_id in _request_body_cache:
111+
try:
112+
del _request_body_cache[request_id]
113+
except KeyError:
114+
pass
115+
else:
116+
# Clear entire cache
117+
_request_body_cache.clear()
118+
119+
93120
def _safe_get_request_parsed_body(request: Optional[Request]) -> Optional[dict]:
94121
if request is None:
95122
return None
123+
124+
# Try to get from cache first
125+
request_id = id(request)
126+
if request_id in _request_body_cache:
127+
return _request_body_cache[request_id]
128+
129+
# Fallback to checking request.scope for backward compatibility
96130
if (
97131
hasattr(request, "scope")
98132
and "parsed_body" in request.scope
99133
and isinstance(request.scope["parsed_body"], tuple)
100134
):
101135
accepted_keys, parsed_body = request.scope["parsed_body"]
102-
return {key: parsed_body[key] for key in accepted_keys}
136+
result = {key: parsed_body[key] for key in accepted_keys}
137+
# Clean up the scope to free memory
138+
del request.scope["parsed_body"]
139+
# Store in our cache for consistency
140+
_request_body_cache[request_id] = result
141+
return result
103142
return None
104143

105144
def _safe_get_request_query_params(request: Optional[Request]) -> Dict:
@@ -122,7 +161,18 @@ def _safe_set_request_parsed_body(
122161
try:
123162
if request is None:
124163
return
125-
request.scope["parsed_body"] = (tuple(parsed_body.keys()), parsed_body)
164+
165+
# Store in cache with size limit to prevent unbounded growth
166+
request_id = id(request)
167+
_request_body_cache[request_id] = parsed_body
168+
169+
# If cache gets too large, remove oldest entries
170+
if len(_request_body_cache) > 1000: # Maximum 1000 cached requests
171+
# Remove the oldest 100 entries
172+
keys_to_remove = list(_request_body_cache.keys())[:100]
173+
for key in keys_to_remove:
174+
del _request_body_cache[key]
175+
126176
except Exception as e:
127177
verbose_proxy_logger.debug(
128178
"Unexpected error setting request parsed body - {}".format(e)

0 commit comments

Comments
 (0)