1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-27 14:31:13 +00:00

Reduce overhead to refire events from async_track_point_in_utc_time when an asyncio timer fires early (#73295)

* Reduce overhead to refire events

- asyncio timers can fire early for a varity of reasons including
  poor clock resolution and performance. To solve this problem
  we re-arm async_track_point_in_utc_time and try again later
  when this happens.

- On some platforms this means the async_track_point_in_utc_time can
  end up trying many times to prevent firing the timer early since as
  soon as it rearms it fires again and this repeats until we reach
  the appointed time. While there is not much we can do to prevent
  asyncio from firing the timer callback early, we can reduce the
  overhead when this happens by using avoiding creating datetime
  objects

* tweak mocking

* -vvv

* fix time freeze being too broad in litterrobot

* adjust
This commit is contained in:
J. Nick Koston
2022-06-14 07:46:00 -10:00
committed by GitHub
parent f69ea6017d
commit 9b157f974d
3 changed files with 19 additions and 14 deletions

View File

@@ -378,7 +378,10 @@ def async_fire_time_changed(
) -> None:
"""Fire a time changed event."""
if datetime_ is None:
datetime_ = date_util.utcnow()
utc_datetime = date_util.utcnow()
else:
utc_datetime = date_util.as_utc(datetime_)
timestamp = date_util.utc_to_timestamp(utc_datetime)
for task in list(hass.loop._scheduled):
if not isinstance(task, asyncio.TimerHandle):
@@ -386,13 +389,16 @@ def async_fire_time_changed(
if task.cancelled():
continue
mock_seconds_into_future = datetime_.timestamp() - time.time()
mock_seconds_into_future = timestamp - time.time()
future_seconds = task.when() - hass.loop.time()
if fire_all or mock_seconds_into_future >= future_seconds:
with patch(
"homeassistant.helpers.event.time_tracker_utcnow",
return_value=date_util.as_utc(datetime_),
return_value=utc_datetime,
), patch(
"homeassistant.helpers.event.time_tracker_timestamp",
return_value=timestamp,
):
task._run()
task.cancel()