Skip to content

Commit 573599d

Browse files
mergify[bot]lesebclaude
authored
perf(routers): parallelize health and vector store fan-out (backport #5802) (#5818)
# What does this PR do? This PR parallelizes router fan-out work to reduce latency when many providers or vector stores are registered. `InferenceRouter.health` and `VectorIORouter.health` now snapshot provider implementations and run per-provider health checks concurrently with `asyncio.gather`, while preserving timeout and error mapping to `HealthResponse`. `VectorIORouter.openai_list_vector_stores` now retrieves registered vector stores concurrently and preserves existing sorting and pagination behavior by filtering failed retrievals. ## Test Plan ```bash uv run pytest tests/unit/core/routers/test_vector_io.py tests/unit/core/routers/test_inference_router.py -q ``` Output: ``` ............ [100%] ============================= slowest 10 durations ============================= (10 durations < 0.005s hidden. Use -vv to show these durations.) 12 passed in 0.23s ``` <hr>This is an automatic backport of pull request #5802 done by [Mergify](https://mergify.com). Signed-off-by: Sébastien Han <seb@redhat.com> Co-authored-by: Sébastien Han <seb@redhat.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 4d0c563 commit 573599d

2 files changed

Lines changed: 34 additions & 32 deletions

File tree

src/ogx/core/routers/inference.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -351,27 +351,27 @@ async def _nonstream_openai_chat_completion(
351351
return response
352352

353353
async def health(self) -> dict[str, HealthResponse]:
354-
health_statuses = {}
355-
timeout = 1 # increasing the timeout to 1 second for health checks
356-
for provider_id, impl in self.routing_table.impls_by_provider_id.items():
354+
timeout = 1
355+
impls_snapshot = dict(self.routing_table.impls_by_provider_id)
356+
357+
async def _check_one(provider_id: str, impl: object) -> tuple[str, HealthResponse]:
357358
try:
358-
# check if the provider has a health method
359359
if not hasattr(impl, "health"):
360-
continue
361-
health = await asyncio.wait_for(impl.health(), timeout=timeout)
362-
health_statuses[provider_id] = health
360+
return provider_id, HealthResponse(status=HealthStatus.NOT_IMPLEMENTED)
361+
result = await asyncio.wait_for(impl.health(), timeout=timeout)
362+
return provider_id, result
363363
except TimeoutError:
364-
health_statuses[provider_id] = HealthResponse(
364+
return provider_id, HealthResponse(
365365
status=HealthStatus.ERROR,
366366
message=f"Health check timed out after {timeout} seconds",
367367
)
368368
except NotImplementedError:
369-
health_statuses[provider_id] = HealthResponse(status=HealthStatus.NOT_IMPLEMENTED)
369+
return provider_id, HealthResponse(status=HealthStatus.NOT_IMPLEMENTED)
370370
except Exception as e:
371-
health_statuses[provider_id] = HealthResponse(
372-
status=HealthStatus.ERROR, message=f"Health check failed: {str(e)}"
373-
)
374-
return health_statuses
371+
return provider_id, HealthResponse(status=HealthStatus.ERROR, message=f"Health check failed: {str(e)}")
372+
373+
results = await asyncio.gather(*[_check_one(pid, impl) for pid, impl in impls_snapshot.items()])
374+
return dict(results)
375375

376376
async def stream_tokens_and_compute_metrics_openai_chat(
377377
self,

src/ogx/core/routers/vector_io.py

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -377,14 +377,16 @@ async def openai_list_vector_stores(
377377
# Route to default provider for now - could aggregate from all providers in the future
378378
# call retrieve on each vector dbs to get list of vector stores
379379
vector_stores = await self.routing_table.get_all_with_type("vector_store")
380-
all_stores = []
381-
for vector_store in vector_stores:
380+
381+
async def _retrieve_safe(identifier: str) -> VectorStoreObject | None:
382382
try:
383-
vector_store_obj = await self.routing_table.openai_retrieve_vector_store(vector_store.identifier)
384-
all_stores.append(vector_store_obj)
383+
return await self.routing_table.openai_retrieve_vector_store(identifier)
385384
except Exception as e:
386-
logger.error("Error retrieving vector store", identifier=vector_store.identifier, error=str(e))
387-
continue
385+
logger.error("Error retrieving vector store", identifier=identifier, error=str(e))
386+
return None
387+
388+
results = await asyncio.gather(*[_retrieve_safe(vs.identifier) for vs in vector_stores])
389+
all_stores = [r for r in results if r is not None]
388390

389391
# Sort by created_at
390392
reverse_order = order == "desc"
@@ -667,27 +669,27 @@ async def openai_delete_vector_store_file(
667669
raise
668670

669671
async def health(self) -> dict[str, HealthResponse]:
670-
health_statuses = {}
671-
timeout = 1 # increasing the timeout to 1 second for health checks
672-
for provider_id, impl in self.routing_table.impls_by_provider_id.items():
672+
timeout = 1
673+
impls_snapshot = dict(self.routing_table.impls_by_provider_id)
674+
675+
async def _check_one(provider_id: str, impl: object) -> tuple[str, HealthResponse]:
673676
try:
674-
# check if the provider has a health method
675677
if not hasattr(impl, "health"):
676-
continue
677-
health = await asyncio.wait_for(impl.health(), timeout=timeout)
678-
health_statuses[provider_id] = health
678+
return provider_id, HealthResponse(status=HealthStatus.NOT_IMPLEMENTED)
679+
result = await asyncio.wait_for(impl.health(), timeout=timeout)
680+
return provider_id, result
679681
except TimeoutError:
680-
health_statuses[provider_id] = HealthResponse(
682+
return provider_id, HealthResponse(
681683
status=HealthStatus.ERROR,
682684
message=f"Health check timed out after {timeout} seconds",
683685
)
684686
except NotImplementedError:
685-
health_statuses[provider_id] = HealthResponse(status=HealthStatus.NOT_IMPLEMENTED)
687+
return provider_id, HealthResponse(status=HealthStatus.NOT_IMPLEMENTED)
686688
except Exception as e:
687-
health_statuses[provider_id] = HealthResponse(
688-
status=HealthStatus.ERROR, message=f"Health check failed: {str(e)}"
689-
)
690-
return health_statuses
689+
return provider_id, HealthResponse(status=HealthStatus.ERROR, message=f"Health check failed: {str(e)}")
690+
691+
results = await asyncio.gather(*[_check_one(pid, impl) for pid, impl in impls_snapshot.items()])
692+
return dict(results)
691693

692694
async def openai_create_vector_store_file_batch(
693695
self,

0 commit comments

Comments
 (0)