Avoid reschedule churn in Storage.async_delay_save (#111091)

* Avoid circular import in Storage.async_delay_save

We call Storage.async_delay_save for every entity being added or removed
from the registry. The late import took more time than everything else
in the function.

* Avoid reschedule churn in Storage.async_delay_save

When we are adding or removing entities we will call async_delay_save
quite often which has to add and remove a TimerHandle on the event loop
which can add up when there are a lot of registry items changing.

If the timer handle still has 80% of the time remaining on it
we will avoid resceduling and let it fire at the time the
original async_delay_save call was made. This ensures we
do not force the event loop to rebuild its heapq because
too many timer handlers were cancelled at once

* div0

* add coverage for 0 since we had none

* fix bad conflict

* tweaks

* tweaks

* tweaks

* tweaks

* tweaks

* tweaks

* more test fixes

* mqtt tests rely on event loop overhead
This commit is contained in:
J. Nick Koston
2024-02-23 21:46:00 -10:00
committed by GitHub
parent ff0e0b3e77
commit 5b8591ec7e
5 changed files with 149 additions and 18 deletions

View File

@ -1400,6 +1400,8 @@ async def test_replaying_payload_same_topic(
hass, "test/state", "online", qos=0, retain=True
) # Simulate a (retained) message played back
await hass.async_block_till_done()
await hass.async_block_till_done()
assert len(calls_a) == 1
mqtt_client_mock.subscribe.assert_called()
calls_a = []
@ -1498,6 +1500,7 @@ async def test_replaying_payload_after_resubscribing(
await hass.async_block_till_done()
async_fire_time_changed(hass, utcnow() + timedelta(seconds=3))
await hass.async_block_till_done()
await hass.async_block_till_done()
mqtt_client_mock.subscribe.assert_called()
# Simulate a (retained) message played back
@ -1638,6 +1641,7 @@ async def test_not_calling_unsubscribe_with_active_subscribers(
await hass.async_block_till_done()
async_fire_time_changed(hass, utcnow() + timedelta(seconds=3)) # cooldown
await hass.async_block_till_done()
await hass.async_block_till_done()
assert mqtt_client_mock.subscribe.called
unsub()