From a968dea1525f1c4f303a6a1055ef8838e96f630e Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Mon, 19 Apr 2021 14:45:01 +0200 Subject: [PATCH] Fix deadlock when restarting scripts (#49410) --- homeassistant/helpers/script.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index 7103fe17ac9..12f75960c41 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -1212,13 +1212,8 @@ class Script: raise async def _async_stop( - self, update_state: bool, spare: _ScriptRun | None = None + self, aws: list[asyncio.Task], update_state: bool, spare: _ScriptRun | None ) -> None: - aws = [ - asyncio.create_task(run.async_stop()) for run in self._runs if run != spare - ] - if not aws: - return await asyncio.wait(aws) if update_state: self._changed() @@ -1227,7 +1222,15 @@ class Script: self, update_state: bool = True, spare: _ScriptRun | None = None ) -> None: """Stop running script.""" - await asyncio.shield(self._async_stop(update_state, spare)) + # Collect a a list of script runs to stop. This must be done before calling + # 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 + ] + if not aws: + return + await asyncio.shield(self._async_stop(aws, update_state, spare)) async def _async_get_condition(self, config): if isinstance(config, template.Template):