Avoid core/supervisor stats API calls when no entities need them (#102362)
This commit is contained in:
parent
af0b53cc79
commit
82c0610050
3 changed files with 68 additions and 41 deletions
|
@ -57,9 +57,6 @@ from .addon_manager import AddonError, AddonInfo, AddonManager, AddonState # no
|
|||
from .addon_panel import async_setup_addon_panel
|
||||
from .auth import async_setup_auth_view
|
||||
from .const import (
|
||||
ADDON_UPDATE_CHANGELOG,
|
||||
ADDON_UPDATE_INFO,
|
||||
ADDON_UPDATE_STATS,
|
||||
ATTR_ADDON,
|
||||
ATTR_ADDONS,
|
||||
ATTR_AUTO_UPDATE,
|
||||
|
@ -76,6 +73,10 @@ from .const import (
|
|||
ATTR_STATE,
|
||||
ATTR_URL,
|
||||
ATTR_VERSION,
|
||||
CONTAINER_CHANGELOG,
|
||||
CONTAINER_INFO,
|
||||
CONTAINER_STATS,
|
||||
CORE_CONTAINER,
|
||||
DATA_KEY_ADDONS,
|
||||
DATA_KEY_CORE,
|
||||
DATA_KEY_HOST,
|
||||
|
@ -83,6 +84,7 @@ from .const import (
|
|||
DATA_KEY_SUPERVISOR,
|
||||
DATA_KEY_SUPERVISOR_ISSUES,
|
||||
DOMAIN,
|
||||
SUPERVISOR_CONTAINER,
|
||||
SupervisorEntityModel,
|
||||
)
|
||||
from .discovery import HassioServiceInfo, async_setup_discovery_view # noqa: F401
|
||||
|
@ -805,9 +807,9 @@ class HassioDataUpdateCoordinator(DataUpdateCoordinator):
|
|||
self.entry_id = config_entry.entry_id
|
||||
self.dev_reg = dev_reg
|
||||
self.is_hass_os = (get_info(self.hass) or {}).get("hassos") is not None
|
||||
self._enabled_updates_by_addon: defaultdict[
|
||||
str, dict[str, set[str]]
|
||||
] = defaultdict(lambda: defaultdict(set))
|
||||
self._container_updates: defaultdict[str, dict[str, set[str]]] = defaultdict(
|
||||
lambda: defaultdict(set)
|
||||
)
|
||||
|
||||
async def _async_update_data(self) -> dict[str, Any]:
|
||||
"""Update data via library."""
|
||||
|
@ -910,23 +912,24 @@ class HassioDataUpdateCoordinator(DataUpdateCoordinator):
|
|||
|
||||
async def force_data_refresh(self, first_update: bool) -> None:
|
||||
"""Force update of the addon info."""
|
||||
container_updates = self._container_updates
|
||||
|
||||
data = self.hass.data
|
||||
hassio = self.hassio
|
||||
(
|
||||
data[DATA_INFO],
|
||||
data[DATA_CORE_INFO],
|
||||
data[DATA_CORE_STATS],
|
||||
data[DATA_SUPERVISOR_INFO],
|
||||
data[DATA_SUPERVISOR_STATS],
|
||||
data[DATA_OS_INFO],
|
||||
) = await asyncio.gather(
|
||||
hassio.get_info(),
|
||||
hassio.get_core_info(),
|
||||
hassio.get_core_stats(),
|
||||
hassio.get_supervisor_info(),
|
||||
hassio.get_supervisor_stats(),
|
||||
hassio.get_os_info(),
|
||||
)
|
||||
updates = {
|
||||
DATA_INFO: hassio.get_info(),
|
||||
DATA_CORE_INFO: hassio.get_core_info(),
|
||||
DATA_SUPERVISOR_INFO: hassio.get_supervisor_info(),
|
||||
DATA_OS_INFO: hassio.get_os_info(),
|
||||
}
|
||||
if first_update or CONTAINER_STATS in container_updates[CORE_CONTAINER]:
|
||||
updates[DATA_CORE_STATS] = hassio.get_core_stats()
|
||||
if first_update or CONTAINER_STATS in container_updates[SUPERVISOR_CONTAINER]:
|
||||
updates[DATA_SUPERVISOR_STATS] = hassio.get_supervisor_stats()
|
||||
|
||||
results = await asyncio.gather(*updates.values())
|
||||
for key, result in zip(updates, results):
|
||||
data[key] = result
|
||||
|
||||
_addon_data = data[DATA_SUPERVISOR_INFO].get("addons", [])
|
||||
all_addons: list[str] = []
|
||||
|
@ -940,37 +943,36 @@ class HassioDataUpdateCoordinator(DataUpdateCoordinator):
|
|||
# Update add-on info if its the first update or
|
||||
# there is at least one entity that needs the data.
|
||||
#
|
||||
# When entities are added they call async_enable_addon_updates
|
||||
# When entities are added they call async_enable_container_updates
|
||||
# to enable updates for the endpoints they need via
|
||||
# async_added_to_hass. This ensures that we only update
|
||||
# the data for the endpoints that are needed to avoid unnecessary
|
||||
# API calls since otherwise we would fetch stats for all add-ons
|
||||
# API calls since otherwise we would fetch stats for all containers
|
||||
# and throw them away.
|
||||
#
|
||||
enabled_updates_by_addon = self._enabled_updates_by_addon
|
||||
for data_key, update_func, enabled_key, wanted_addons in (
|
||||
(
|
||||
DATA_ADDONS_STATS,
|
||||
self._update_addon_stats,
|
||||
ADDON_UPDATE_STATS,
|
||||
CONTAINER_STATS,
|
||||
started_addons,
|
||||
),
|
||||
(
|
||||
DATA_ADDONS_CHANGELOGS,
|
||||
self._update_addon_changelog,
|
||||
ADDON_UPDATE_CHANGELOG,
|
||||
CONTAINER_CHANGELOG,
|
||||
all_addons,
|
||||
),
|
||||
(DATA_ADDONS_INFO, self._update_addon_info, ADDON_UPDATE_INFO, all_addons),
|
||||
(DATA_ADDONS_INFO, self._update_addon_info, CONTAINER_INFO, all_addons),
|
||||
):
|
||||
data.setdefault(data_key, {}).update(
|
||||
container_data: dict[str, Any] = data.setdefault(data_key, {})
|
||||
container_data.update(
|
||||
dict(
|
||||
await asyncio.gather(
|
||||
*[
|
||||
update_func(slug)
|
||||
for slug in wanted_addons
|
||||
if first_update
|
||||
or enabled_key in enabled_updates_by_addon[slug]
|
||||
if first_update or enabled_key in container_updates[slug]
|
||||
]
|
||||
)
|
||||
)
|
||||
|
@ -1004,11 +1006,11 @@ class HassioDataUpdateCoordinator(DataUpdateCoordinator):
|
|||
return (slug, None)
|
||||
|
||||
@callback
|
||||
def async_enable_addon_updates(
|
||||
def async_enable_container_updates(
|
||||
self, slug: str, entity_id: str, types: set[str]
|
||||
) -> CALLBACK_TYPE:
|
||||
"""Enable updates for an add-on."""
|
||||
enabled_updates = self._enabled_updates_by_addon[slug]
|
||||
enabled_updates = self._container_updates[slug]
|
||||
for key in types:
|
||||
enabled_updates[key].add(entity_id)
|
||||
|
||||
|
|
|
@ -82,19 +82,22 @@ PLACEHOLDER_KEY_COMPONENTS = "components"
|
|||
|
||||
ISSUE_KEY_SYSTEM_DOCKER_CONFIG = "issue_system_docker_config"
|
||||
|
||||
ADDON_UPDATE_STATS = "stats"
|
||||
ADDON_UPDATE_CHANGELOG = "changelog"
|
||||
ADDON_UPDATE_INFO = "info"
|
||||
CORE_CONTAINER = "homeassistant"
|
||||
SUPERVISOR_CONTAINER = "hassio_supervisor"
|
||||
|
||||
CONTAINER_STATS = "stats"
|
||||
CONTAINER_CHANGELOG = "changelog"
|
||||
CONTAINER_INFO = "info"
|
||||
|
||||
# This is a mapping of which endpoint the key in the addon data
|
||||
# is obtained from so we know which endpoint to update when the
|
||||
# coordinator polls for updates.
|
||||
KEY_TO_UPDATE_TYPES: dict[str, set[str]] = {
|
||||
ATTR_VERSION_LATEST: {ADDON_UPDATE_INFO, ADDON_UPDATE_CHANGELOG},
|
||||
ATTR_MEMORY_PERCENT: {ADDON_UPDATE_STATS},
|
||||
ATTR_CPU_PERCENT: {ADDON_UPDATE_STATS},
|
||||
ATTR_VERSION: {ADDON_UPDATE_INFO},
|
||||
ATTR_STATE: {ADDON_UPDATE_INFO},
|
||||
ATTR_VERSION_LATEST: {CONTAINER_INFO, CONTAINER_CHANGELOG},
|
||||
ATTR_MEMORY_PERCENT: {CONTAINER_STATS},
|
||||
ATTR_CPU_PERCENT: {CONTAINER_STATS},
|
||||
ATTR_VERSION: {CONTAINER_INFO},
|
||||
ATTR_STATE: {CONTAINER_INFO},
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -10,12 +10,14 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
|||
from . import DOMAIN, HassioDataUpdateCoordinator
|
||||
from .const import (
|
||||
ATTR_SLUG,
|
||||
CORE_CONTAINER,
|
||||
DATA_KEY_ADDONS,
|
||||
DATA_KEY_CORE,
|
||||
DATA_KEY_HOST,
|
||||
DATA_KEY_OS,
|
||||
DATA_KEY_SUPERVISOR,
|
||||
KEY_TO_UPDATE_TYPES,
|
||||
SUPERVISOR_CONTAINER,
|
||||
)
|
||||
|
||||
|
||||
|
@ -52,7 +54,7 @@ class HassioAddonEntity(CoordinatorEntity[HassioDataUpdateCoordinator]):
|
|||
await super().async_added_to_hass()
|
||||
update_types = KEY_TO_UPDATE_TYPES[self.entity_description.key]
|
||||
self.async_on_remove(
|
||||
self.coordinator.async_enable_addon_updates(
|
||||
self.coordinator.async_enable_container_updates(
|
||||
self._addon_slug, self.entity_id, update_types
|
||||
)
|
||||
)
|
||||
|
@ -136,6 +138,16 @@ class HassioSupervisorEntity(CoordinatorEntity[HassioDataUpdateCoordinator]):
|
|||
in self.coordinator.data[DATA_KEY_SUPERVISOR]
|
||||
)
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Subscribe to updates."""
|
||||
await super().async_added_to_hass()
|
||||
update_types = KEY_TO_UPDATE_TYPES[self.entity_description.key]
|
||||
self.async_on_remove(
|
||||
self.coordinator.async_enable_container_updates(
|
||||
SUPERVISOR_CONTAINER, self.entity_id, update_types
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class HassioCoreEntity(CoordinatorEntity[HassioDataUpdateCoordinator]):
|
||||
"""Base Entity for Core."""
|
||||
|
@ -161,3 +173,13 @@ class HassioCoreEntity(CoordinatorEntity[HassioDataUpdateCoordinator]):
|
|||
and DATA_KEY_CORE in self.coordinator.data
|
||||
and self.entity_description.key in self.coordinator.data[DATA_KEY_CORE]
|
||||
)
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Subscribe to updates."""
|
||||
await super().async_added_to_hass()
|
||||
update_types = KEY_TO_UPDATE_TYPES[self.entity_description.key]
|
||||
self.async_on_remove(
|
||||
self.coordinator.async_enable_container_updates(
|
||||
CORE_CONTAINER, self.entity_id, update_types
|
||||
)
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue