Skip to content

Commit fd7808e

Browse files
committed
Implement pass-through route registration and removal to prevent duplicates and memory leaks
1 parent 758fe45 commit fd7808e

File tree

1 file changed

+60
-0
lines changed

1 file changed

+60
-0
lines changed

litellm/proxy/pass_through_endpoints/pass_through_endpoints.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@
5757

5858
pass_through_endpoint_logging = PassThroughEndpointLogging()
5959

60+
# Global registry to track registered pass-through routes and prevent memory leaks
61+
_registered_pass_through_routes: Dict[str, Dict[str, str]] = {}
62+
6063

6164
def get_response_body(response: httpx.Response) -> Optional[dict]:
6265
try:
@@ -952,8 +955,19 @@ def add_exact_path_route(
952955
merge_query_params: Optional[bool],
953956
dependencies: Optional[List],
954957
cost_per_request: Optional[float],
958+
endpoint_id: str,
955959
):
956960
"""Add exact path route for pass-through endpoint"""
961+
route_key = f"{endpoint_id}:exact:{path}"
962+
963+
# Check if this exact route is already registered
964+
if route_key in _registered_pass_through_routes:
965+
verbose_proxy_logger.debug(
966+
"Skipping duplicate exact pass through endpoint: %s (already registered)",
967+
path,
968+
)
969+
return
970+
957971
verbose_proxy_logger.debug(
958972
"adding exact pass through endpoint: %s, dependencies: %s",
959973
path,
@@ -974,6 +988,13 @@ def add_exact_path_route(
974988
methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
975989
dependencies=dependencies,
976990
)
991+
992+
# Register the route to prevent duplicates
993+
_registered_pass_through_routes[route_key] = {
994+
"endpoint_id": endpoint_id,
995+
"path": path,
996+
"type": "exact"
997+
}
977998

978999
@staticmethod
9791000
def add_subpath_route(
@@ -985,9 +1006,20 @@ def add_subpath_route(
9851006
merge_query_params: Optional[bool],
9861007
dependencies: Optional[List],
9871008
cost_per_request: Optional[float],
1009+
endpoint_id: str,
9881010
):
9891011
"""Add wildcard route for sub-paths"""
9901012
wildcard_path = f"{path}/{{subpath:path}}"
1013+
route_key = f"{endpoint_id}:subpath:{path}"
1014+
1015+
# Check if this subpath route is already registered
1016+
if route_key in _registered_pass_through_routes:
1017+
verbose_proxy_logger.debug(
1018+
"Skipping duplicate wildcard pass through endpoint: %s (already registered)",
1019+
wildcard_path,
1020+
)
1021+
return
1022+
9911023
verbose_proxy_logger.debug(
9921024
"adding wildcard pass through endpoint: %s, dependencies: %s",
9931025
wildcard_path,
@@ -1009,6 +1041,26 @@ def add_subpath_route(
10091041
methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
10101042
dependencies=dependencies,
10111043
)
1044+
1045+
# Register the route to prevent duplicates
1046+
_registered_pass_through_routes[route_key] = {
1047+
"endpoint_id": endpoint_id,
1048+
"path": path,
1049+
"type": "subpath"
1050+
}
1051+
1052+
@staticmethod
1053+
def remove_endpoint_routes(endpoint_id: str):
1054+
"""Remove all routes for a specific endpoint ID from the registry"""
1055+
keys_to_remove = [
1056+
key for key, value in _registered_pass_through_routes.items()
1057+
if value["endpoint_id"] == endpoint_id
1058+
]
1059+
for key in keys_to_remove:
1060+
del _registered_pass_through_routes[key]
1061+
verbose_proxy_logger.debug(
1062+
"Removed pass-through route from registry: %s", key
1063+
)
10121064

10131065

10141066
async def initialize_pass_through_endpoints(
@@ -1072,6 +1124,7 @@ async def initialize_pass_through_endpoints(
10721124
merge_query_params=_merge_query_params,
10731125
dependencies=_dependencies,
10741126
cost_per_request=endpoint.get("cost_per_request", None),
1127+
endpoint_id=endpoint.get("id"),
10751128
)
10761129

10771130
# Add wildcard route for sub-paths
@@ -1085,6 +1138,7 @@ async def initialize_pass_through_endpoints(
10851138
merge_query_params=_merge_query_params,
10861139
dependencies=_dependencies,
10871140
cost_per_request=endpoint.get("cost_per_request", None),
1141+
endpoint_id=endpoint.get("id"),
10881142
)
10891143

10901144
verbose_proxy_logger.debug("Added new pass through endpoint: %s (ID: %s)", _path, endpoint.get("id"))
@@ -1229,6 +1283,9 @@ async def update_pass_through_endpoints(
12291283
# Update the list
12301284
pass_through_endpoint_data[endpoint_index] = endpoint_dict
12311285

1286+
# Remove old routes from registry before they get re-registered
1287+
InitPassThroughEndpointHelpers.remove_endpoint_routes(endpoint_id)
1288+
12321289
## Update db
12331290
updated_data = ConfigFieldUpdate(
12341291
field_name="pass_through_endpoints",
@@ -1369,6 +1426,9 @@ async def delete_pass_through_endpoints(
13691426
pass_through_endpoint_data.pop(endpoint_index)
13701427
response_obj = found_endpoint
13711428

1429+
# Remove routes from registry
1430+
InitPassThroughEndpointHelpers.remove_endpoint_routes(endpoint_id)
1431+
13721432
## Update db
13731433
updated_data = ConfigFieldUpdate(
13741434
field_name="pass_through_endpoints",

0 commit comments

Comments
 (0)