From f80894d56f5e8213dc571bdab4b8aaccfc862c5c Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 10 Apr 2024 02:41:13 -1000 Subject: [PATCH] Stop scripts with eager tasks (#115340) --- homeassistant/helpers/script.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index 3c364ed8892..ea5cc3e571a 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -1250,7 +1250,7 @@ async def _async_stop_scripts_after_shutdown( _LOGGER.warning("Stopping scripts running too long after shutdown: %s", names) await asyncio.gather( *( - script["instance"].async_stop(update_state=False) + create_eager_task(script["instance"].async_stop(update_state=False)) for script in running_scripts ) ) @@ -1269,7 +1269,10 @@ async def _async_stop_scripts_at_shutdown(hass: HomeAssistant, event: Event) -> names = ", ".join([script["instance"].name for script in running_scripts]) _LOGGER.debug("Stopping scripts running at shutdown: %s", names) await asyncio.gather( - *(script["instance"].async_stop() for script in running_scripts) + *( + create_eager_task(script["instance"].async_stop()) + for script in running_scripts + ) ) @@ -1695,6 +1698,9 @@ class Script: # return false after the other script runs were stopped until our task # resumes running. self._log("Restarting") + # Important: yield to the event loop to allow the script to start in case + # the script is restarting itself. + await asyncio.sleep(0) await self.async_stop(update_state=False, spare=run) if started_action: @@ -1724,11 +1730,13 @@ class Script: # asyncio.shield as asyncio.shield yields to the event loop, which would cause # us to wait for script runs added after the call to async_stop. aws = [ - asyncio.create_task(run.async_stop()) for run in self._runs if run != spare + create_eager_task(run.async_stop()) for run in self._runs if run != spare ] if not aws: return - await asyncio.shield(self._async_stop(aws, update_state, spare)) + await asyncio.shield( + create_eager_task(self._async_stop(aws, update_state, spare)) + ) async def _async_get_condition(self, config): if isinstance(config, template.Template):