Suppress domain and all listeners during template rate limit (#42005)
This commit is contained in:
parent
344514601d
commit
3a9b2392f8
2 changed files with 87 additions and 2 deletions
|
@ -1,5 +1,6 @@
|
||||||
"""Helpers for listening to events."""
|
"""Helpers for listening to events."""
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import copy
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import functools as ft
|
import functools as ft
|
||||||
|
@ -820,6 +821,8 @@ class _TrackTemplateResultInfo:
|
||||||
if not _event_triggers_rerender(event, info):
|
if not _event_triggers_rerender(event, info):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
had_timer = self._rate_limit.async_has_timer(template)
|
||||||
|
|
||||||
if self._rate_limit.async_schedule_action(
|
if self._rate_limit.async_schedule_action(
|
||||||
template,
|
template,
|
||||||
_rate_limit_for_event(event, info, track_template_),
|
_rate_limit_for_event(event, info, track_template_),
|
||||||
|
@ -829,7 +832,7 @@ class _TrackTemplateResultInfo:
|
||||||
(track_template_,),
|
(track_template_,),
|
||||||
True,
|
True,
|
||||||
):
|
):
|
||||||
return False
|
return not had_timer
|
||||||
|
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Template update %s triggered by event: %s",
|
"Template update %s triggered by event: %s",
|
||||||
|
@ -893,7 +896,14 @@ class _TrackTemplateResultInfo:
|
||||||
if info_changed:
|
if info_changed:
|
||||||
assert self._track_state_changes
|
assert self._track_state_changes
|
||||||
self._track_state_changes.async_update_listeners(
|
self._track_state_changes.async_update_listeners(
|
||||||
_render_infos_to_track_states(self._info.values()),
|
_render_infos_to_track_states(
|
||||||
|
[
|
||||||
|
_suppress_domain_all_in_render_info(self._info[template])
|
||||||
|
if self._rate_limit.async_has_timer(template)
|
||||||
|
else self._info[template]
|
||||||
|
for template in self._info
|
||||||
|
]
|
||||||
|
)
|
||||||
)
|
)
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Template group %s listens for %s",
|
"Template group %s listens for %s",
|
||||||
|
@ -1458,3 +1468,13 @@ def _rate_limit_for_event(
|
||||||
|
|
||||||
rate_limit: Optional[timedelta] = info.rate_limit
|
rate_limit: Optional[timedelta] = info.rate_limit
|
||||||
return rate_limit
|
return rate_limit
|
||||||
|
|
||||||
|
|
||||||
|
def _suppress_domain_all_in_render_info(render_info: RenderInfo) -> RenderInfo:
|
||||||
|
"""Remove the domains and all_states from render info during a ratelimit."""
|
||||||
|
rate_limited_render_info = copy.copy(render_info)
|
||||||
|
rate_limited_render_info.all_states = False
|
||||||
|
rate_limited_render_info.all_states_lifecycle = False
|
||||||
|
rate_limited_render_info.domains = set()
|
||||||
|
rate_limited_render_info.domains_lifecycle = set()
|
||||||
|
return rate_limited_render_info
|
||||||
|
|
|
@ -1494,6 +1494,71 @@ async def test_track_template_rate_limit(hass):
|
||||||
assert refresh_runs == [0, 1, 2, 4]
|
assert refresh_runs == [0, 1, 2, 4]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_track_template_rate_limit_suppress_listener(hass):
|
||||||
|
"""Test template rate limit will suppress the listener during the rate limit."""
|
||||||
|
template_refresh = Template("{{ states | count }}", hass)
|
||||||
|
|
||||||
|
refresh_runs = []
|
||||||
|
|
||||||
|
@ha.callback
|
||||||
|
def refresh_listener(event, updates):
|
||||||
|
refresh_runs.append(updates.pop().result)
|
||||||
|
|
||||||
|
info = async_track_template_result(
|
||||||
|
hass,
|
||||||
|
[TrackTemplate(template_refresh, None, timedelta(seconds=0.1))],
|
||||||
|
refresh_listener,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
info.async_refresh()
|
||||||
|
|
||||||
|
assert info.listeners == {"all": True, "domains": set(), "entities": set()}
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert refresh_runs == [0]
|
||||||
|
hass.states.async_set("sensor.one", "any")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert refresh_runs == [0]
|
||||||
|
info.async_refresh()
|
||||||
|
assert refresh_runs == [0, 1]
|
||||||
|
hass.states.async_set("sensor.two", "any")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
# Should be suppressed during the rate limit
|
||||||
|
assert info.listeners == {"all": False, "domains": set(), "entities": set()}
|
||||||
|
assert refresh_runs == [0, 1]
|
||||||
|
next_time = dt_util.utcnow() + timedelta(seconds=0.125)
|
||||||
|
with patch(
|
||||||
|
"homeassistant.helpers.ratelimit.dt_util.utcnow", return_value=next_time
|
||||||
|
):
|
||||||
|
async_fire_time_changed(hass, next_time)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
# Rate limit released and the all listener returns
|
||||||
|
assert info.listeners == {"all": True, "domains": set(), "entities": set()}
|
||||||
|
assert refresh_runs == [0, 1, 2]
|
||||||
|
hass.states.async_set("sensor.three", "any")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert refresh_runs == [0, 1, 2]
|
||||||
|
hass.states.async_set("sensor.four", "any")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert refresh_runs == [0, 1, 2]
|
||||||
|
# Rate limit hit and the all listener is shut off
|
||||||
|
assert info.listeners == {"all": False, "domains": set(), "entities": set()}
|
||||||
|
next_time = dt_util.utcnow() + timedelta(seconds=0.125 * 2)
|
||||||
|
with patch(
|
||||||
|
"homeassistant.helpers.ratelimit.dt_util.utcnow", return_value=next_time
|
||||||
|
):
|
||||||
|
async_fire_time_changed(hass, next_time)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
# Rate limit released and the all listener returns
|
||||||
|
assert info.listeners == {"all": True, "domains": set(), "entities": set()}
|
||||||
|
assert refresh_runs == [0, 1, 2, 4]
|
||||||
|
hass.states.async_set("sensor.five", "any")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
# Rate limit hit and the all listener is shut off
|
||||||
|
assert info.listeners == {"all": False, "domains": set(), "entities": set()}
|
||||||
|
assert refresh_runs == [0, 1, 2, 4]
|
||||||
|
|
||||||
|
|
||||||
async def test_track_template_rate_limit_five(hass):
|
async def test_track_template_rate_limit_five(hass):
|
||||||
"""Test template rate limit of 5 seconds."""
|
"""Test template rate limit of 5 seconds."""
|
||||||
template_refresh = Template("{{ states | count }}", hass)
|
template_refresh = Template("{{ states | count }}", hass)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue