1 """Run Home Assistant."""
3 from __future__
import annotations
10 from time
import monotonic
12 from typing
import Any
16 from .
import bootstrap
17 from .core
import callback
18 from .helpers.frame
import warn_use
19 from .util.executor
import InterruptibleThreadPoolExecutor
20 from .util.thread
import deadlock_safe_shutdown
32 MAX_EXECUTOR_WORKERS = 64
33 TASK_CANCELATION_TIMEOUT = 5
35 _LOGGER = logging.getLogger(__name__)
38 @dataclasses.dataclass(slots=True)
40 """Class to hold the information for running Home Assistant."""
43 skip_pip: bool =
False
44 skip_pip_packages: list[str] = dataclasses.field(default_factory=list)
45 recovery_mode: bool =
False
49 log_rotate_days: int |
None =
None
50 log_file: str |
None =
None
51 log_no_color: bool =
False
56 safe_mode: bool =
False
60 """Event loop policy for Home Assistant."""
63 """Init the event loop policy."""
69 """Return name of the loop."""
70 return self._loop_factory.__name__
73 """Get the event loop."""
75 loop.set_exception_handler(_async_loop_exception_handler)
80 thread_name_prefix=
"SyncWorker", max_workers=MAX_EXECUTOR_WORKERS
82 loop.set_default_executor(executor)
83 loop.set_default_executor = warn_use(
84 loop.set_default_executor,
"sets default executor on the event loop"
95 """Handle all exception inside the core loop."""
97 if exception := context.get(
"exception"):
98 kwargs[
"exc_info"] = (type(exception), exception, exception.__traceback__)
100 logger = logging.getLogger(__package__)
101 if source_traceback := context.get(
"source_traceback"):
102 stack_summary =
"".join(traceback.format_list(source_traceback))
104 "Error doing job: %s (%s): %s",
113 "Error doing job: %s (%s)",
121 """Set up Home Assistant and run."""
122 hass = await bootstrap.async_setup_hass(runtime_config)
128 threading._shutdown = deadlock_safe_shutdown
130 return await hass.async_run()
134 """Enable posix_spawn on Alpine Linux."""
135 if subprocess._USE_POSIX_SPAWN:
142 tag = next(packaging.tags.sys_tags())
143 subprocess._USE_POSIX_SPAWN =
"musllinux" in tag.platform
146 def run(runtime_config: RuntimeConfig) -> int:
147 """Run Home Assistant."""
151 loop = asyncio.new_event_loop()
153 asyncio.set_event_loop(loop)
158 loop.run_until_complete(loop.shutdown_asyncgens())
159 loop.run_until_complete(loop.shutdown_default_executor())
161 asyncio.set_event_loop(
None)
166 loop: asyncio.AbstractEventLoop, timeout: int
168 """Adapted _cancel_all_tasks from python 3.9 with a timeout."""
169 to_cancel = asyncio.all_tasks(loop)
173 for task
in to_cancel:
174 task.cancel(
"Final process shutdown")
176 loop.run_until_complete(asyncio.wait(to_cancel, timeout=timeout))
178 for task
in to_cancel:
183 "Task could not be canceled and was still running after shutdown: %s",
187 if task.exception()
is not None:
188 loop.call_exception_handler(
190 "message":
"unhandled exception during shutdown",
191 "exception": task.exception(),
asyncio.AbstractEventLoop new_event_loop(self)
None __init__(self, bool debug)
int setup_and_run_hass(RuntimeConfig runtime_config)
None _async_loop_exception_handler(Any _, dict[str, Any] context)
int run(RuntimeConfig runtime_config)
None _enable_posix_spawn()
None _cancel_all_tasks_with_timeout(asyncio.AbstractEventLoop loop, int timeout)