57
57
58
58
pass_through_endpoint_logging = PassThroughEndpointLogging ()
59
59
60
+ # Global registry to track registered pass-through routes and prevent memory leaks
61
+ _registered_pass_through_routes : Dict [str , Dict [str , str ]] = {}
62
+
60
63
61
64
def get_response_body (response : httpx .Response ) -> Optional [dict ]:
62
65
try :
@@ -952,8 +955,19 @@ def add_exact_path_route(
952
955
merge_query_params : Optional [bool ],
953
956
dependencies : Optional [List ],
954
957
cost_per_request : Optional [float ],
958
+ endpoint_id : str ,
955
959
):
956
960
"""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
+
957
971
verbose_proxy_logger .debug (
958
972
"adding exact pass through endpoint: %s, dependencies: %s" ,
959
973
path ,
@@ -974,6 +988,13 @@ def add_exact_path_route(
974
988
methods = ["GET" , "POST" , "PUT" , "DELETE" , "PATCH" ],
975
989
dependencies = dependencies ,
976
990
)
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
+ }
977
998
978
999
@staticmethod
979
1000
def add_subpath_route (
@@ -985,9 +1006,20 @@ def add_subpath_route(
985
1006
merge_query_params : Optional [bool ],
986
1007
dependencies : Optional [List ],
987
1008
cost_per_request : Optional [float ],
1009
+ endpoint_id : str ,
988
1010
):
989
1011
"""Add wildcard route for sub-paths"""
990
1012
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
+
991
1023
verbose_proxy_logger .debug (
992
1024
"adding wildcard pass through endpoint: %s, dependencies: %s" ,
993
1025
wildcard_path ,
@@ -1009,6 +1041,26 @@ def add_subpath_route(
1009
1041
methods = ["GET" , "POST" , "PUT" , "DELETE" , "PATCH" ],
1010
1042
dependencies = dependencies ,
1011
1043
)
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
+ )
1012
1064
1013
1065
1014
1066
async def initialize_pass_through_endpoints (
@@ -1072,6 +1124,7 @@ async def initialize_pass_through_endpoints(
1072
1124
merge_query_params = _merge_query_params ,
1073
1125
dependencies = _dependencies ,
1074
1126
cost_per_request = endpoint .get ("cost_per_request" , None ),
1127
+ endpoint_id = endpoint .get ("id" ),
1075
1128
)
1076
1129
1077
1130
# Add wildcard route for sub-paths
@@ -1085,6 +1138,7 @@ async def initialize_pass_through_endpoints(
1085
1138
merge_query_params = _merge_query_params ,
1086
1139
dependencies = _dependencies ,
1087
1140
cost_per_request = endpoint .get ("cost_per_request" , None ),
1141
+ endpoint_id = endpoint .get ("id" ),
1088
1142
)
1089
1143
1090
1144
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(
1229
1283
# Update the list
1230
1284
pass_through_endpoint_data [endpoint_index ] = endpoint_dict
1231
1285
1286
+ # Remove old routes from registry before they get re-registered
1287
+ InitPassThroughEndpointHelpers .remove_endpoint_routes (endpoint_id )
1288
+
1232
1289
## Update db
1233
1290
updated_data = ConfigFieldUpdate (
1234
1291
field_name = "pass_through_endpoints" ,
@@ -1369,6 +1426,9 @@ async def delete_pass_through_endpoints(
1369
1426
pass_through_endpoint_data .pop (endpoint_index )
1370
1427
response_obj = found_endpoint
1371
1428
1429
+ # Remove routes from registry
1430
+ InitPassThroughEndpointHelpers .remove_endpoint_routes (endpoint_id )
1431
+
1372
1432
## Update db
1373
1433
updated_data = ConfigFieldUpdate (
1374
1434
field_name = "pass_through_endpoints" ,
0 commit comments