Ensure recorder shuts down when its startup future is canceled out from under it (#72866)

This commit is contained in:
J. Nick Koston 2022-06-01 19:13:09 -10:00 committed by GitHub
parent d368b9e24f
commit f79e5e002b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 3 deletions

View file

@ -3,6 +3,7 @@ from __future__ import annotations
import asyncio import asyncio
from collections.abc import Callable, Iterable from collections.abc import Callable, Iterable
from concurrent.futures import CancelledError
import contextlib import contextlib
from datetime import datetime, timedelta from datetime import datetime, timedelta
import logging import logging
@ -518,9 +519,16 @@ class Recorder(threading.Thread):
def _wait_startup_or_shutdown(self) -> object | None: def _wait_startup_or_shutdown(self) -> object | None:
"""Wait for startup or shutdown before starting.""" """Wait for startup or shutdown before starting."""
return asyncio.run_coroutine_threadsafe( try:
self._async_wait_for_started(), self.hass.loop return asyncio.run_coroutine_threadsafe(
).result() self._async_wait_for_started(), self.hass.loop
).result()
except CancelledError as ex:
_LOGGER.warning(
"Recorder startup was externally canceled before it could complete: %s",
ex,
)
return SHUTDOWN_TASK
def run(self) -> None: def run(self) -> None:
"""Start processing events to save.""" """Start processing events to save."""

View file

@ -118,6 +118,26 @@ async def test_shutdown_before_startup_finishes(
assert run_info.end is not None assert run_info.end is not None
async def test_canceled_before_startup_finishes(
hass: HomeAssistant,
async_setup_recorder_instance: SetupRecorderInstanceT,
caplog: pytest.LogCaptureFixture,
):
"""Test recorder shuts down when its startup future is canceled out from under it."""
hass.state = CoreState.not_running
await async_setup_recorder_instance(hass)
instance = get_instance(hass)
await instance.async_db_ready
instance._hass_started.cancel()
with patch.object(instance, "engine"):
await hass.async_block_till_done()
await hass.async_add_executor_job(instance.join)
assert (
"Recorder startup was externally canceled before it could complete"
in caplog.text
)
async def test_shutdown_closes_connections(hass, recorder_mock): async def test_shutdown_closes_connections(hass, recorder_mock):
"""Test shutdown closes connections.""" """Test shutdown closes connections."""