diff --git a/supervisor/__main__.py b/supervisor/__main__.py index 2db75bd8d..a6d2cf9ee 100644 --- a/supervisor/__main__.py +++ b/supervisor/__main__.py @@ -5,6 +5,7 @@ import logging import sys from supervisor import bootstrap +from supervisor.const import CoreState _LOGGER: logging.Logger = logging.getLogger(__name__) @@ -47,14 +48,15 @@ if __name__ == "__main__": loop.run_until_complete(coresys.core.setup()) loop.call_soon_threadsafe(loop.create_task, coresys.core.start()) - loop.call_soon_threadsafe(bootstrap.reg_signal, loop) + loop.call_soon_threadsafe(bootstrap.reg_signal, loop, coresys) try: _LOGGER.info("Run Supervisor") loop.run_forever() finally: - _LOGGER.info("Stopping Supervisor") - loop.run_until_complete(coresys.core.stop()) + if coresys.core.state != CoreState.CLOSE: + _LOGGER.info("Stopping Supervisor") + loop.run_until_complete(coresys.core.stop()) executor.shutdown(wait=False) loop.close() diff --git a/supervisor/bootstrap.py b/supervisor/bootstrap.py index 24e110ee6..9e4f80ed3 100644 --- a/supervisor/bootstrap.py +++ b/supervisor/bootstrap.py @@ -240,20 +240,26 @@ def check_environment() -> None: _LOGGER.critical("Can't find gdbus!") -def reg_signal(loop) -> None: +def reg_signal(loop, coresys: CoreSys) -> None: """Register SIGTERM and SIGKILL to stop system.""" try: - loop.add_signal_handler(signal.SIGTERM, lambda: loop.call_soon(loop.stop)) + loop.add_signal_handler( + signal.SIGTERM, lambda: loop.create_task(coresys.core.stop()) + ) except (ValueError, RuntimeError): _LOGGER.warning("Could not bind to SIGTERM") try: - loop.add_signal_handler(signal.SIGHUP, lambda: loop.call_soon(loop.stop)) + loop.add_signal_handler( + signal.SIGHUP, lambda: loop.create_task(coresys.core.stop()) + ) except (ValueError, RuntimeError): _LOGGER.warning("Could not bind to SIGHUP") try: - loop.add_signal_handler(signal.SIGINT, lambda: loop.call_soon(loop.stop)) + loop.add_signal_handler( + signal.SIGINT, lambda: loop.create_task(coresys.core.stop()) + ) except (ValueError, RuntimeError): _LOGGER.warning("Could not bind to SIGINT") diff --git a/supervisor/const.py b/supervisor/const.py index df5e20f7f..a4d75b73b 100644 --- a/supervisor/const.py +++ b/supervisor/const.py @@ -395,7 +395,9 @@ class CoreState(str, Enum): STARTUP = "startup" RUNNING = "running" FREEZE = "freeze" + SHUTDOWN = "shutdown" STOPPING = "stopping" + CLOSE = "close" class LogLevel(str, Enum): diff --git a/supervisor/core.py b/supervisor/core.py index 9012c6788..a17326aee 100644 --- a/supervisor/core.py +++ b/supervisor/core.py @@ -241,8 +241,10 @@ class Core(CoreSysAttributes): async def stop(self): """Stop a running orchestration.""" # store new last boot / prevent time adjustments - if self.state == CoreState.RUNNING: + if self.state in (CoreState.RUNNING, CoreState.SHUTDOWN): self._update_last_boot() + if self.state in (CoreState.STOPPING, CoreState.CLOSE): + return # don't process scheduler anymore self.state = CoreState.STOPPING @@ -269,12 +271,14 @@ class Core(CoreSysAttributes): _LOGGER.warning("Stage 2: Force Shutdown!") _LOGGER.info("Supervisor is down") + self.state = CoreState.CLOSE + self.sys_loop.stop() async def shutdown(self): """Shutdown all running containers in correct order.""" # don't process scheduler anymore if self.state == CoreState.RUNNING: - self.state = CoreState.STOPPING + self.state = CoreState.SHUTDOWN # Shutdown Application Add-ons, using Home Assistant API await self.sys_addons.shutdown(AddonStartup.APPLICATION) @@ -289,7 +293,7 @@ class Core(CoreSysAttributes): await self.sys_addons.shutdown(AddonStartup.INITIALIZE) # Shutdown all Plugins - if self.state == CoreState.STOPPING: + if self.state in (CoreState.STOPPING, CoreState.SHUTDOWN): await self.sys_plugins.shutdown() def _update_last_boot(self): diff --git a/supervisor/misc/scheduler.py b/supervisor/misc/scheduler.py index 03b1ea9e0..ee9433d6d 100644 --- a/supervisor/misc/scheduler.py +++ b/supervisor/misc/scheduler.py @@ -61,7 +61,10 @@ class Scheduler(CoreSysAttributes): if self.sys_core.state == CoreState.RUNNING: await task.coro_callback() finally: - if task.repeat and self.sys_core.state != CoreState.STOPPING: + if task.repeat and self.sys_core.state not in ( + CoreState.STOPPING, + CoreState.CLOSE, + ): self._schedule_task(task) else: self._tasks.remove(task) diff --git a/supervisor/supervisor.py b/supervisor/supervisor.py index 9fdd58b49..a79279b02 100644 --- a/supervisor/supervisor.py +++ b/supervisor/supervisor.py @@ -124,7 +124,7 @@ class Supervisor(CoreSysAttributes): with suppress(SupervisorError): await self.update_apparmor() - self.sys_loop.call_later(5, self.sys_loop.stop) + self.sys_create_task(self.sys_core.stop()) @property def in_progress(self) -> bool: