@@ -279,6 +279,7 @@ async def get_project_backends_with_models(project: ProjectModel) -> List[Backen
279279 async with _get_project_cache_lock (project .id ):
280280 key = project .id
281281 project_backends = _BACKENDS_CACHE .get (key , {})
282+ to_init : List [Tuple [BackendModel , Configurator , StoredBackendRecord ]] = []
282283 for backend_model in project .backends :
283284 cached_backend = project_backends .get (backend_model .type )
284285 if (
@@ -300,16 +301,41 @@ async def get_project_backends_with_models(project: ProjectModel) -> List[Backen
300301 backend_model .type .value ,
301302 )
302303 continue
303- try :
304- backend_record = get_stored_backend_record (backend_model )
305- backend = await run_async (configurator .get_backend , backend_record )
306- except (BackendInvalidCredentialsError , BackendAuthError ):
307- logger .warning (
308- "Credentials for %s backend are invalid. Backend will be ignored." ,
309- backend_model .type .value ,
310- )
311- continue
312- project_backends [backend_model .type ] = (backend_model , backend )
304+ backend_record = get_stored_backend_record (backend_model )
305+ to_init .append ((backend_model , configurator , backend_record ))
306+
307+ if to_init :
308+ t0 = time .time ()
309+ tasks = [
310+ _get_backend_tracked (configurator , backend_record )
311+ for _ , configurator , backend_record in to_init
312+ ]
313+ results = await asyncio .gather (* tasks , return_exceptions = True )
314+ initialized_results = []
315+ for (backend_model , _ , _ ), result in zip (to_init , results ):
316+ if isinstance (result , BaseException ):
317+ if isinstance (result , (BackendInvalidCredentialsError , BackendAuthError )):
318+ logger .warning (
319+ "Credentials for %s backend are invalid. Backend will be ignored." ,
320+ backend_model .type .value ,
321+ )
322+ else :
323+ logger .error (
324+ "Failed to initialize %s backend. Backend will be ignored." ,
325+ backend_model .type .value ,
326+ exc_info = result ,
327+ )
328+ else :
329+ backend , duration = result
330+ project_backends [backend_model .type ] = (backend_model , backend )
331+ initialized_results .append (f"{ backend_model .type .value } ={ duration :.1f} s" )
332+ logger .debug (
333+ "Initialized %d backends in %.1fs: %s" ,
334+ len (initialized_results ),
335+ time .time () - t0 ,
336+ ", " .join (initialized_results ),
337+ )
338+
313339 # `__setitem__()` will also expire the cache.
314340 # Note that there is no global cache lock so a race condition is possible:
315341 # one coroutine updates/re-assigns backends expired by another coroutine.
@@ -318,6 +344,14 @@ async def get_project_backends_with_models(project: ProjectModel) -> List[Backen
318344 return list (project_backends .values ())
319345
320346
347+ async def _get_backend_tracked (
348+ configurator : Configurator , backend_record : StoredBackendRecord
349+ ) -> Tuple [Backend , float ]:
350+ t = time .time ()
351+ backend = await run_async (configurator .get_backend , backend_record )
352+ return backend , time .time () - t
353+
354+
321355_get_project_backend_with_model_by_type = None
322356
323357
0 commit comments