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:
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user