2323import time
2424from urllib .parse import urljoin
2525
26- from inference_endpoint .core .types import Query
26+ from inference_endpoint .core .types import Query , QueryResult
2727from inference_endpoint .endpoint_client .configs import (
2828 AioHttpConfig ,
2929 HTTPClientConfig ,
3030 ZMQConfig ,
3131)
32- from inference_endpoint .endpoint_client .futures_client import FuturesHttpClient
32+ from inference_endpoint .endpoint_client .http_client import HTTPEndpointClient
3333from inference_endpoint .exceptions import (
3434 ExecutionError ,
3535 InputValidationError ,
@@ -80,14 +80,16 @@ async def run_probe_command(args: argparse.Namespace) -> None:
8080 zmq_readiness_queue_addr = f"ipc://{ tmp_dir } /ready" ,
8181 )
8282
83- client = FuturesHttpClient (http_config , aiohttp_config , zmq_config )
84- await client .async_start ()
83+ client = HTTPEndpointClient (http_config , aiohttp_config , zmq_config )
84+
85+ # Start client in separate thread
86+ await asyncio .get_event_loop ().run_in_executor (None , client .start )
8587
8688 logger .info (f"Sending { num_requests } requests..." )
8789
88- # Send test requests and collect futures
89- futures = []
90+ # Send test requests
9091 start_times = {}
92+ sent_query_ids = []
9193
9294 # TODO: this might not work with a real vLLM/SGLang endpoint, fix this.
9395 for i in range (num_requests ):
@@ -101,10 +103,10 @@ async def run_probe_command(args: argparse.Namespace) -> None:
101103 },
102104 )
103105 start_times [f"probe-{ i } " ] = time .time ()
106+ sent_query_ids .append (f"probe-{ i } " )
104107
105108 try :
106- future = await client .issue_query (query )
107- futures .append ((f"probe-{ i } " , future ))
109+ client .issue_query (query )
108110 # Simple progress indicator
109111 if (i + 1 ) % max (1 , num_requests // 10 ) == 0 or i == num_requests - 1 :
110112 logger .info (f" Issued { i + 1 } /{ num_requests } requests" )
@@ -117,34 +119,67 @@ async def run_probe_command(args: argparse.Namespace) -> None:
117119 responses = []
118120
119121 # Wait for all responses with generous timeout (probe queries can be slow)
120- # Default HTTP client timeout is 30s, give extra buffer for processing
121- probe_timeout = 60.0 # 60 seconds per query
122+ probe_timeout = 60.0 # 60 seconds total
123+ start_wait = time .time ()
124+
125+ logger .info (f"Waiting for { num_requests } responses..." )
122126
123- logger . info ( f"Waiting for { len ( futures ) } responses..." )
127+ received_ids = set ( )
124128
125- for idx , (query_id , future ) in enumerate (futures ):
129+ while (
130+ len (received_ids ) < num_requests
131+ and (time .time () - start_wait ) < probe_timeout
132+ ):
126133 try :
127- result = await asyncio .wait_for (future , timeout = probe_timeout )
128- # Calculate latency - should always be in start_times
129- assert (
130- query_id in start_times
131- ), f"Query { query_id } not found in start_times"
132- latency_ms = (time .time () - start_times [query_id ]) * 1000
133- latencies .append (latency_ms )
134+ # Get response from client
135+ result : (
136+ QueryResult | None
137+ ) = await asyncio .get_event_loop ().run_in_executor (
138+ None , client .get_ready_responses
139+ )
140+
141+ if result is None :
142+ await asyncio .sleep (0.01 )
143+ continue
144+
145+ query_id = result .id
146+
147+ if query_id in received_ids :
148+ logger .warning (f"Received duplicate response for { query_id } " )
149+ continue
150+
151+ received_ids .add (query_id )
152+
153+ # Calculate latency
154+ if query_id in start_times :
155+ latency_ms = (time .time () - start_times [query_id ]) * 1000
134156
135157 if result .error :
136158 errors .append (f"{ query_id } : { result .error } " )
137159 else :
160+ # Only count successful responses in latencies
161+ if query_id in start_times :
162+ latencies .append (latency_ms )
138163 # Store successful response for sanity check
139164 responses .append ((query_id , result .response_output ))
140- except TimeoutError :
141- errors .append (f"{ query_id } : Timeout (>{ probe_timeout } s)" )
165+
166+ # Simple progress indicator
167+ if (
168+ len (received_ids ) % max (1 , num_requests // 10 ) == 0
169+ or len (received_ids ) == num_requests
170+ ):
171+ logger .info (
172+ f" Processed { len (received_ids )} /{ num_requests } responses"
173+ )
174+
142175 except Exception as e :
143- errors .append (f"{ query_id } : { str (e )[:50 ]} " )
176+ logger .warning (f"Error receiving response: { str (e )[:50 ]} " )
177+ await asyncio .sleep (0.01 )
144178
145- # Simple progress indicator
146- if (idx + 1 ) % max (1 , len (futures ) // 10 ) == 0 or idx == len (futures ) - 1 :
147- logger .info (f" Processed { idx + 1 } /{ len (futures )} responses" )
179+ # Mark any not received as timeout
180+ for query_id in sent_query_ids :
181+ if query_id not in received_ids :
182+ errors .append (f"{ query_id } : Timeout (>{ probe_timeout } s)" )
148183
149184 # Report results
150185 success_count = len (latencies )
@@ -192,5 +227,5 @@ async def run_probe_command(args: argparse.Namespace) -> None:
192227 finally :
193228 # Cleanup
194229 if client is not None :
195- await client . async_shutdown ( )
230+ await asyncio . get_event_loop (). run_in_executor ( None , client . shutdown )
196231 shutil .rmtree (tmp_dir , ignore_errors = True )
0 commit comments