Reduce overhead to fetch integrations (#93767)

We call this path over and over during startup and most
of the time the integration is already loaded. We want
that case to be the short path
pull/93774/head
J. Nick Koston 2023-05-29 19:58:51 -05:00 committed by GitHub
parent 1ea202a5bc
commit 53fe74e055
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 21 additions and 18 deletions

View File

@ -891,14 +891,15 @@ async def async_get_integrations(
results: dict[str, Integration | Exception] = {} results: dict[str, Integration | Exception] = {}
needed: dict[str, asyncio.Future[None]] = {} needed: dict[str, asyncio.Future[None]] = {}
in_progress: dict[str, asyncio.Future[None]] = {} in_progress: dict[str, asyncio.Future[None]] = {}
if TYPE_CHECKING:
cache = cast(dict[str, Integration | asyncio.Future[None]], cache)
for domain in domains: for domain in domains:
int_or_fut: Integration | asyncio.Future[None] | None = cache.get( int_or_fut = cache.get(domain, _UNDEF)
domain, _UNDEF # Integration is never subclassed, so we can check for type
) if type(int_or_fut) is Integration: # pylint: disable=unidiomatic-typecheck
if isinstance(int_or_fut, asyncio.Future): results[domain] = int_or_fut
in_progress[domain] = int_or_fut
elif int_or_fut is not _UNDEF: elif int_or_fut is not _UNDEF:
results[domain] = cast(Integration, int_or_fut) in_progress[domain] = cast(asyncio.Future[None], int_or_fut)
elif "." in domain: elif "." in domain:
results[domain] = ValueError(f"Invalid domain {domain}") results[domain] = ValueError(f"Invalid domain {domain}")
else: else:
@ -915,19 +916,21 @@ async def async_get_integrations(
else: else:
results[domain] = cast(Integration, int_or_fut) results[domain] = cast(Integration, int_or_fut)
# First we look for custom components if not needed:
if needed: return results
# Instead of using resolve_from_root we use the cache of custom
# components to find the integration.
custom = await async_get_custom_components(hass)
for domain, future in needed.items():
if integration := custom.get(domain):
results[domain] = cache[domain] = integration
future.set_result(None)
for domain in results: # First we look for custom components
if domain in needed: # Instead of using resolve_from_root we use the cache of custom
del needed[domain] # components to find the integration.
custom = await async_get_custom_components(hass)
for domain, future in needed.items():
if integration := custom.get(domain):
results[domain] = cache[domain] = integration
future.set_result(None)
for domain in results:
if domain in needed:
del needed[domain]
# Now the rest use resolve_from_root # Now the rest use resolve_from_root
if needed: if needed: