From 8cb62341ef352bfc20eb9bd5dace81b84b01d112 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 14 Apr 2025 09:42:23 -1000 Subject: [PATCH] Fix race to rename entity (#142584) --- homeassistant/components/recorder/__init__.py | 2 +- .../components/recorder/entity_registry.py | 20 ++++++++++--------- tests/components/recorder/test_init.py | 20 +++++++++++++++++++ 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/recorder/__init__.py b/homeassistant/components/recorder/__init__.py index 7cb71e70f65..c0bffbe9615 100644 --- a/homeassistant/components/recorder/__init__.py +++ b/homeassistant/components/recorder/__init__.py @@ -170,12 +170,12 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: exclude_event_types=exclude_event_types, ) get_instance.cache_clear() + entity_registry.async_setup(hass) instance.async_initialize() instance.async_register() instance.start() async_register_services(hass, instance) websocket_api.async_setup(hass) - entity_registry.async_setup(hass) await _async_setup_integration_platform(hass, instance) diff --git a/homeassistant/components/recorder/entity_registry.py b/homeassistant/components/recorder/entity_registry.py index 07f8f2f88de..30a3a1b8239 100644 --- a/homeassistant/components/recorder/entity_registry.py +++ b/homeassistant/components/recorder/entity_registry.py @@ -4,8 +4,9 @@ import logging from typing import TYPE_CHECKING from homeassistant.core import Event, HomeAssistant, callback +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import entity_registry as er -from homeassistant.helpers.start import async_at_start +from homeassistant.helpers.event import async_has_entity_registry_updated_listeners from .core import Recorder from .util import filter_unique_constraint_integrity_error, get_instance, session_scope @@ -40,16 +41,17 @@ def async_setup(hass: HomeAssistant) -> None: """Handle entity_id changed filter.""" return event_data["action"] == "update" and "old_entity_id" in event_data - @callback - def _setup_entity_registry_event_handler(hass: HomeAssistant) -> None: - """Subscribe to event registry events.""" - hass.bus.async_listen( - er.EVENT_ENTITY_REGISTRY_UPDATED, - _async_entity_id_changed, - event_filter=entity_registry_changed_filter, + if async_has_entity_registry_updated_listeners(hass): + raise HomeAssistantError( + "The recorder entity registry listener must be installed" + " before async_track_entity_registry_updated_event is called" ) - async_at_start(hass, _setup_entity_registry_event_handler) + hass.bus.async_listen( + er.EVENT_ENTITY_REGISTRY_UPDATED, + _async_entity_id_changed, + event_filter=entity_registry_changed_filter, + ) def update_states_metadata( diff --git a/tests/components/recorder/test_init.py b/tests/components/recorder/test_init.py index 95cd959db3b..2023e15176f 100644 --- a/tests/components/recorder/test_init.py +++ b/tests/components/recorder/test_init.py @@ -77,6 +77,7 @@ from homeassistant.helpers import ( issue_registry as ir, recorder as recorder_helper, ) +from homeassistant.helpers.event import async_track_entity_registry_updated_event from homeassistant.helpers.typing import ConfigType from homeassistant.setup import async_setup_component from homeassistant.util import dt as dt_util @@ -2798,3 +2799,22 @@ async def test_empty_entity_id( hass.bus.async_fire("hello", {"entity_id": ""}) await async_wait_recording_done(hass) assert "Invalid entity ID" not in caplog.text + + +async def test_setting_up_recorder_fails_entity_registry_listener( + hass: HomeAssistant, caplog: pytest.LogCaptureFixture +) -> None: + """Test recorder setup fails if an entity registry listener is in place.""" + async_track_entity_registry_updated_event(hass, "test.test", lambda x: x) + recorder_helper.async_initialize_recorder(hass) + with patch("homeassistant.components.recorder.ALLOW_IN_MEMORY_DB", True): + assert not await async_setup_component( + hass, + recorder.DOMAIN, + {recorder.DOMAIN: {recorder.CONF_DB_URL: "sqlite://"}}, + ) + await hass.async_block_till_done() + assert ( + "The recorder entity registry listener must be installed before " + "async_track_entity_registry_updated_event is called" in caplog.text + )