Improve logging of _TrackPointUTCTime objects (#116711)

This commit is contained in:
J. Nick Koston 2024-05-04 17:35:44 -05:00 committed by GitHub
parent 910c991a58
commit 0380116ef6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 34 additions and 4 deletions

View file

@ -1436,12 +1436,18 @@ class _TrackPointUTCTime:
"""Initialize track job.""" """Initialize track job."""
loop = self.hass.loop loop = self.hass.loop
self._cancel_callback = loop.call_at( self._cancel_callback = loop.call_at(
loop.time() + self.expected_fire_timestamp - time.time(), self._run_action loop.time() + self.expected_fire_timestamp - time.time(), self
) )
@callback @callback
def _run_action(self) -> None: def __call__(self) -> None:
"""Call the action.""" """Call the action.
We implement this as __call__ so when debug logging logs the object
it shows the name of the job. This is especially helpful when asyncio
debug logging is enabled as we can see the name of the job that is
being called that is blocking the event loop.
"""
# Depending on the available clock support (including timer hardware # Depending on the available clock support (including timer hardware
# and the OS kernel) it can happen that we fire a little bit too early # and the OS kernel) it can happen that we fire a little bit too early
# as measured by utcnow(). That is bad when callbacks have assumptions # as measured by utcnow(). That is bad when callbacks have assumptions
@ -1450,7 +1456,7 @@ class _TrackPointUTCTime:
if (delta := (self.expected_fire_timestamp - time_tracker_timestamp())) > 0: if (delta := (self.expected_fire_timestamp - time_tracker_timestamp())) > 0:
_LOGGER.debug("Called %f seconds too early, rearming", delta) _LOGGER.debug("Called %f seconds too early, rearming", delta)
loop = self.hass.loop loop = self.hass.loop
self._cancel_callback = loop.call_at(loop.time() + delta, self._run_action) self._cancel_callback = loop.call_at(loop.time() + delta, self)
return return
self.hass.async_run_hass_job(self.job, self.utc_point_in_time) self.hass.async_run_hass_job(self.job, self.utc_point_in_time)

View file

@ -4819,3 +4819,21 @@ async def test_track_state_change_deprecated(
"of `async_track_state_change_event` which is deprecated and " "of `async_track_state_change_event` which is deprecated and "
"will be removed in Home Assistant 2025.5. Please report this issue." "will be removed in Home Assistant 2025.5. Please report this issue."
) in caplog.text ) in caplog.text
async def test_track_point_in_time_repr(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
"""Test track point in time."""
@ha.callback
def _raise_exception(_):
raise RuntimeError("something happened and its poorly described")
async_track_point_in_utc_time(hass, _raise_exception, dt_util.utcnow())
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
assert "Exception in callback _TrackPointUTCTime" in caplog.text
assert "._raise_exception" in caplog.text
await hass.async_block_till_done(wait_background_tasks=True)

View file

@ -7,6 +7,12 @@ IGNORE_UNCAUGHT_EXCEPTIONS = [
"tests.test_runner", "tests.test_runner",
"test_unhandled_exception_traceback", "test_unhandled_exception_traceback",
), ),
(
# This test explicitly throws an uncaught exception
# and should not be removed.
"tests.helpers.test_event",
"test_track_point_in_time_repr",
),
( (
"test_homeassistant_bridge", "test_homeassistant_bridge",
"test_homeassistant_bridge_fan_setup", "test_homeassistant_bridge_fan_setup",