1
0
mirror of https://github.com/home-assistant/supervisor.git synced 2025-12-24 20:35:55 +00:00

Cancel Supervisor startup task on early shutdown signal (#6175)

When receiving a shutdown signal during startup, the Supervisor should
cancel its startup task to ensure a graceful shutdown. This prevents
Supervisor accidentally accessing the Event loop after it has been
closed by the stop procedure:

RuntimeError: Event loop stopped before Future completed.
This commit is contained in:
Stefan Agner
2025-09-16 11:32:43 +02:00
committed by GitHub
parent ac9947d599
commit d2ddd9579c
2 changed files with 22 additions and 12 deletions

View File

@@ -66,10 +66,23 @@ if __name__ == "__main__":
_LOGGER.info("Setting up Supervisor")
loop.run_until_complete(coresys.core.setup())
bootstrap.register_signal_handlers(loop, coresys)
# Create startup task that can be cancelled gracefully
startup_task = loop.create_task(coresys.core.start())
def shutdown_handler() -> None:
"""Handle shutdown signals gracefully during startup."""
if not startup_task.done():
_LOGGER.warning("Supervisor startup interrupted by shutdown signal")
startup_task.cancel()
coresys.create_task(coresys.core.stop())
bootstrap.register_signal_handlers(loop, shutdown_handler)
try:
loop.run_until_complete(coresys.core.start())
loop.run_until_complete(startup_task)
except asyncio.CancelledError:
_LOGGER.warning("Supervisor startup cancelled")
except Exception as err: # pylint: disable=broad-except
# Supervisor itself is running at this point, just something didn't
# start as expected. Log with traceback to get more insights for

View File

@@ -2,6 +2,7 @@
# ruff: noqa: T100
import asyncio
from collections.abc import Callable
from importlib import import_module
import logging
import os
@@ -289,26 +290,22 @@ def check_environment() -> None:
_LOGGER.critical("Can't find Docker socket!")
def register_signal_handlers(loop: asyncio.AbstractEventLoop, coresys: CoreSys) -> None:
def register_signal_handlers(
loop: asyncio.AbstractEventLoop, shutdown_handler: Callable[[], None]
) -> None:
"""Register SIGTERM, SIGHUP and SIGKILL to stop the Supervisor."""
try:
loop.add_signal_handler(
signal.SIGTERM, lambda: loop.create_task(coresys.core.stop())
)
loop.add_signal_handler(signal.SIGTERM, shutdown_handler)
except (ValueError, RuntimeError):
_LOGGER.warning("Could not bind to SIGTERM")
try:
loop.add_signal_handler(
signal.SIGHUP, lambda: loop.create_task(coresys.core.stop())
)
loop.add_signal_handler(signal.SIGHUP, shutdown_handler)
except (ValueError, RuntimeError):
_LOGGER.warning("Could not bind to SIGHUP")
try:
loop.add_signal_handler(
signal.SIGINT, lambda: loop.create_task(coresys.core.stop())
)
loop.add_signal_handler(signal.SIGINT, shutdown_handler)
except (ValueError, RuntimeError):
_LOGGER.warning("Could not bind to SIGINT")