Ensure all async_track_state_change_event callbacks run if one throws (#37179)

This commit is contained in:
J. Nick Koston 2020-06-27 19:48:27 -05:00 committed by GitHub
parent c1194c90cb
commit a63a11a11a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 18 additions and 1 deletions

View File

@ -1,6 +1,7 @@
"""Helpers for listening to events."""
from datetime import datetime, timedelta
import functools as ft
import logging
from typing import Any, Awaitable, Callable, Dict, Iterable, Optional, Union
import attr
@ -24,6 +25,8 @@ from homeassistant.util.async_ import run_callback_threadsafe
TRACK_STATE_CHANGE_CALLBACKS = "track_state_change_callbacks"
TRACK_STATE_CHANGE_LISTENER = "track_state_change_listener"
_LOGGER = logging.getLogger(__name__)
# PyLint does not like the use of threaded_listener_factory
# pylint: disable=invalid-name
@ -146,7 +149,12 @@ def async_track_state_change_event(
return
for action in entity_callbacks[entity_id]:
hass.async_run_job(action, event)
try:
hass.async_run_job(action, event)
except Exception: # pylint: disable=broad-except
_LOGGER.exception(
"Error while processing state changed for %s", entity_id
)
hass.data[TRACK_STATE_CHANGE_LISTENER] = hass.bus.async_listen(
EVENT_STATE_CHANGED, _async_state_change_dispatcher

View File

@ -183,12 +183,19 @@ async def test_async_track_state_change_event(hass):
multiple_entity_id_tracker.append((old_state, new_state))
@ha.callback
def callback_that_throws(event):
raise ValueError
unsub_single = async_track_state_change_event(
hass, ["light.Bowl"], single_run_callback
)
unsub_multi = async_track_state_change_event(
hass, ["light.Bowl", "switch.kitchen"], multiple_run_callback
)
unsub_throws = async_track_state_change_event(
hass, ["light.Bowl", "switch.kitchen"], callback_that_throws
)
# Adding state to state machine
hass.states.async_set("light.Bowl", "on")
@ -247,6 +254,7 @@ async def test_async_track_state_change_event(hass):
assert len(multiple_entity_id_tracker) == 7
unsub_multi()
unsub_throws()
async def test_track_template(hass):
@ -429,6 +437,7 @@ async def test_track_same_state_simple_trigger_check_funct(hass):
# Adding state to state machine
hass.states.async_set("light.Bowl", "on")
await hass.async_block_till_done()
await hass.async_block_till_done()
assert len(callback_runs) == 0
assert check_func[-1][2].state == "on"
assert check_func[-1][0] == "light.bowl"