Add more debug details to running timeouts (#43644)

Co-authored-by: Franck Nijhof <git@frenck.dev>
This commit is contained in:
Pascal Vizeli 2021-01-04 13:10:39 +01:00 committed by GitHub
parent 5b67030c26
commit a7a4875f52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 70 additions and 6 deletions

View File

@ -381,7 +381,7 @@ def _get_domains(hass: core.HomeAssistant, config: Dict[str, Any]) -> Set[str]:
async def _async_log_pending_setups(
domains: Set[str], setup_started: Dict[str, datetime]
hass: core.HomeAssistant, domains: Set[str], setup_started: Dict[str, datetime]
) -> None:
"""Periodic log of setups that are pending for longer than LOG_SLOW_STARTUP_INTERVAL."""
while True:
@ -393,6 +393,7 @@ async def _async_log_pending_setups(
"Waiting on integrations to complete setup: %s",
", ".join(remaining),
)
_LOGGER.debug("Running timeout Zones: %s", hass.timeout.zones)
async def async_setup_multi_components(
@ -406,7 +407,9 @@ async def async_setup_multi_components(
domain: hass.async_create_task(async_setup_component(hass, domain, config))
for domain in domains
}
log_task = asyncio.create_task(_async_log_pending_setups(domains, setup_started))
log_task = asyncio.create_task(
_async_log_pending_setups(hass, domains, setup_started)
)
await asyncio.wait(futures.values())
log_task.cancel()
errors = [domain for domain in domains if futures[domain].exception()]

View File

@ -49,14 +49,14 @@ class _GlobalFreezeContext:
self._loop.call_soon_threadsafe(self._enter)
return self
def __exit__(
def __exit__( # pylint: disable=useless-return
self,
exc_type: Type[BaseException],
exc_val: BaseException,
exc_tb: TracebackType,
) -> Optional[bool]:
self._loop.call_soon_threadsafe(self._exit)
return True
return None
def _enter(self) -> None:
"""Run freeze."""
@ -117,14 +117,14 @@ class _ZoneFreezeContext:
self._loop.call_soon_threadsafe(self._enter)
return self
def __exit__(
def __exit__( # pylint: disable=useless-return
self,
exc_type: Type[BaseException],
exc_val: BaseException,
exc_tb: TracebackType,
) -> Optional[bool]:
self._loop.call_soon_threadsafe(self._exit)
return True
return None
def _enter(self) -> None:
"""Run freeze."""
@ -347,6 +347,10 @@ class _ZoneTimeoutManager:
self._tasks: List[_ZoneTaskContext] = []
self._freezes: List[_ZoneFreezeContext] = []
def __repr__(self) -> str:
"""Representation of a zone."""
return f"<{self.name}: {len(self._tasks)} / {len(self._freezes)}>"
@property
def name(self) -> str:
"""Return Zone name."""

View File

@ -266,3 +266,60 @@ async def test_mix_zone_timeout_trigger_global_cool_down():
pass
await asyncio.sleep(0.2)
async def test_simple_zone_timeout_freeze_without_timeout_cleanup(hass):
"""Test a simple zone timeout freeze on a zone that does not have a timeout set."""
timeout = TimeoutManager()
async def background():
async with timeout.async_freeze("test"):
await asyncio.sleep(0.4)
async with timeout.async_timeout(0.1):
hass.async_create_task(background())
await asyncio.sleep(0.2)
async def test_simple_zone_timeout_freeze_without_timeout_cleanup2(hass):
"""Test a simple zone timeout freeze on a zone that does not have a timeout set."""
timeout = TimeoutManager()
async def background():
async with timeout.async_freeze("test"):
await asyncio.sleep(0.2)
with pytest.raises(asyncio.TimeoutError):
async with timeout.async_timeout(0.1):
hass.async_create_task(background())
await asyncio.sleep(0.3)
async def test_simple_zone_timeout_freeze_without_timeout_exeption():
"""Test a simple zone timeout freeze on a zone that does not have a timeout set."""
timeout = TimeoutManager()
with pytest.raises(asyncio.TimeoutError):
async with timeout.async_timeout(0.1):
try:
async with timeout.async_freeze("test"):
raise RuntimeError()
except RuntimeError:
pass
await asyncio.sleep(0.4)
async def test_simple_zone_timeout_zone_with_timeout_exeption():
"""Test a simple zone timeout freeze on a zone that does not have a timeout set."""
timeout = TimeoutManager()
with pytest.raises(asyncio.TimeoutError):
async with timeout.async_timeout(0.1):
try:
async with timeout.async_timeout(0.3, "test"):
raise RuntimeError()
except RuntimeError:
pass
await asyncio.sleep(0.3)