From a5a62154d4f53f42e116cc9bc722302798b1b326 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 | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index 52be3866639..f2afe152569 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -1203,12 +1203,9 @@ class Script: self._changed() raise - async def _async_stop(self, update_state, spare=None): - aws = [ - asyncio.create_task(run.async_stop()) for run in self._runs if run != spare - ] - if not aws: - return + async def _async_stop( + self, aws: list[asyncio.Task], update_state: bool, spare: _ScriptRun | None + ) -> None: await asyncio.wait(aws) if update_state: self._changed() @@ -1217,7 +1214,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):