Avoid overloading the executor with service.yaml loads (#42172)

This commit is contained in:
J. Nick Koston 2020-10-21 15:24:50 -05:00 committed by GitHub
parent 43aaf91799
commit 4a0d18ccd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -38,7 +38,7 @@ from homeassistant.helpers import template
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.template import Template from homeassistant.helpers.template import Template
from homeassistant.helpers.typing import ConfigType, HomeAssistantType, TemplateVarsType from homeassistant.helpers.typing import ConfigType, HomeAssistantType, TemplateVarsType
from homeassistant.loader import async_get_integration, bind_hass from homeassistant.loader import Integration, async_get_integration, bind_hass
from homeassistant.util.yaml import load_yaml from homeassistant.util.yaml import load_yaml
from homeassistant.util.yaml.loader import JSON_TYPE from homeassistant.util.yaml.loader import JSON_TYPE
@ -252,21 +252,29 @@ async def async_extract_entity_ids(
return extracted return extracted
async def _load_services_file(hass: HomeAssistantType, domain: str) -> JSON_TYPE: def _load_services_file(hass: HomeAssistantType, integration: Integration) -> JSON_TYPE:
"""Load services file for an integration.""" """Load services file for an integration."""
integration = await async_get_integration(hass, domain)
try: try:
return await hass.async_add_executor_job( return load_yaml(str(integration.file_path / "services.yaml"))
load_yaml, str(integration.file_path / "services.yaml")
)
except FileNotFoundError: except FileNotFoundError:
_LOGGER.warning("Unable to find services.yaml for the %s integration", domain) _LOGGER.warning(
"Unable to find services.yaml for the %s integration", integration.domain
)
return {} return {}
except HomeAssistantError: except HomeAssistantError:
_LOGGER.warning("Unable to parse services.yaml for the %s integration", domain) _LOGGER.warning(
"Unable to parse services.yaml for the %s integration", integration.domain
)
return {} return {}
def _load_services_files(
hass: HomeAssistantType, integrations: Iterable[Integration]
) -> List[JSON_TYPE]:
"""Load service files for multiple intergrations."""
return [_load_services_file(hass, integration) for integration in integrations]
@bind_hass @bind_hass
async def async_get_all_descriptions( async def async_get_all_descriptions(
hass: HomeAssistantType, hass: HomeAssistantType,
@ -289,8 +297,12 @@ async def async_get_all_descriptions(
loaded = {} loaded = {}
if missing: if missing:
contents = await asyncio.gather( integrations = await asyncio.gather(
*(_load_services_file(hass, domain) for domain in missing) *(async_get_integration(hass, domain) for domain in missing)
)
contents = await hass.async_add_executor_job(
_load_services_files, hass, integrations
) )
for domain, content in zip(missing, contents): for domain, content in zip(missing, contents):
@ -308,7 +320,7 @@ async def async_get_all_descriptions(
# Cache missing descriptions # Cache missing descriptions
if description is None: if description is None:
domain_yaml = loaded[domain] domain_yaml = loaded[domain]
yaml_description = domain_yaml.get(service, {}) yaml_description = domain_yaml.get(service, {}) # type: ignore
# Don't warn for missing services, because it triggers false # Don't warn for missing services, because it triggers false
# positives for things like scripts, that register as a service # positives for things like scripts, that register as a service