From 3d1556a4a2701065bde7401f9d78e0ce045817bb Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 8 Apr 2023 16:22:56 -1000 Subject: [PATCH] Switch back to using call_later for the slow entity update warning (#91067) * Switch back to using call_later for the slow entity update warning I had originally changed this to create a task and wait in #41184 but that does not make sense anymore with newer cpython as the profile now shows the original method is cheaper (or I did it wrong the first time) * fix missing block till done since there is no longer a task being created which would run the event loop once --- homeassistant/helpers/entity.py | 54 +++++++++---------- .../components/dlna_dmr/test_media_player.py | 1 + 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py index fd9c6bb260d..8352c1e4463 100644 --- a/homeassistant/helpers/entity.py +++ b/homeassistant/helpers/entity.py @@ -723,6 +723,15 @@ class Entity(ABC): else: self.async_write_ha_state() + @callback + def _async_slow_update_warning(self) -> None: + """Log a warning if update is taking too long.""" + _LOGGER.warning( + "Update of %s is taking over %s seconds", + self.entity_id, + SLOW_UPDATE_WARNING, + ) + async def async_device_update(self, warning: bool = True) -> None: """Process 'update' or 'async_update' from entity. @@ -730,42 +739,33 @@ class Entity(ABC): """ if self._update_staged: return + + hass = self.hass + assert hass is not None + + if hasattr(self, "async_update"): + coro: asyncio.Future[None] = self.async_update() + elif hasattr(self, "update"): + coro = hass.async_add_executor_job(self.update) + else: + return + self._update_staged = True # Process update sequential if self.parallel_updates: await self.parallel_updates.acquire() - try: - task: asyncio.Future[None] - if hasattr(self, "async_update"): - task = self.hass.async_create_task( - self.async_update(), f"Entity async update {self.entity_id}" - ) - elif hasattr(self, "update"): - task = self.hass.async_add_executor_job(self.update) - else: - return - - if not warning: - await task - return - - finished, _ = await asyncio.wait([task], timeout=SLOW_UPDATE_WARNING) - - for done in finished: - if exc := done.exception(): - raise exc - return - - _LOGGER.warning( - "Update of %s is taking over %s seconds", - self.entity_id, - SLOW_UPDATE_WARNING, + if warning: + update_warn = hass.loop.call_later( + SLOW_UPDATE_WARNING, self._async_slow_update_warning ) - await task + try: + await coro finally: self._update_staged = False + if warning: + update_warn.cancel() if self.parallel_updates: self.parallel_updates.release() diff --git a/tests/components/dlna_dmr/test_media_player.py b/tests/components/dlna_dmr/test_media_player.py index 83e4e21e16f..e07e0b6cfcb 100644 --- a/tests/components/dlna_dmr/test_media_player.py +++ b/tests/components/dlna_dmr/test_media_player.py @@ -1274,6 +1274,7 @@ async def test_unavailable_device( hass.config_entries.async_update_entry( config_entry_mock, options={CONF_POLL_AVAILABILITY: True} ) + await hass.async_block_till_done() await async_update_entity(hass, mock_entity_id) domain_data_mock.upnp_factory.async_create_device.assert_awaited_once_with( MOCK_DEVICE_LOCATION