From 41eca416389a7b4dc819a22cf555545dbfc534c9 Mon Sep 17 00:00:00 2001 From: karwosts <32912880+karwosts@users.noreply.github.com> Date: Fri, 4 Aug 2023 05:08:49 -0700 Subject: [PATCH] Handle Alert exception on notification failure (#93632) --- homeassistant/components/alert/__init__.py | 13 ++++++++++--- tests/components/alert/test_init.py | 21 +++++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/alert/__init__.py b/homeassistant/components/alert/__init__.py index 9b3fb0f29c8..721ed0d0c21 100644 --- a/homeassistant/components/alert/__init__.py +++ b/homeassistant/components/alert/__init__.py @@ -26,6 +26,7 @@ from homeassistant.const import ( STATE_ON, ) from homeassistant.core import HassJob, HomeAssistant +from homeassistant.exceptions import ServiceNotFound import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent @@ -293,9 +294,15 @@ class Alert(Entity): LOGGER.debug(msg_payload) for target in self._notifiers: - await self.hass.services.async_call( - DOMAIN_NOTIFY, target, msg_payload, context=self._context - ) + try: + await self.hass.services.async_call( + DOMAIN_NOTIFY, target, msg_payload, context=self._context + ) + except ServiceNotFound: + LOGGER.error( + "Failed to call notify.%s, retrying at next notification interval", + target, + ) async def async_turn_on(self, **kwargs: Any) -> None: """Async Unacknowledge alert.""" diff --git a/tests/components/alert/test_init.py b/tests/components/alert/test_init.py index 550727a2a22..8dfbb437646 100644 --- a/tests/components/alert/test_init.py +++ b/tests/components/alert/test_init.py @@ -36,6 +36,7 @@ from tests.common import async_mock_service NAME = "alert_test" DONE_MESSAGE = "alert_gone" NOTIFIER = "test" +BAD_NOTIFIER = "bad_notifier" TEMPLATE = "{{ states.sensor.test.entity_id }}" TEST_ENTITY = "sensor.test" TITLE = "{{ states.sensor.test.entity_id }}" @@ -199,6 +200,26 @@ async def test_notification( assert len(mock_notifier) == 2 +async def test_bad_notifier( + hass: HomeAssistant, mock_notifier: list[ServiceCall] +) -> None: + """Test a broken notifier does not break the alert.""" + config = deepcopy(TEST_CONFIG) + config[DOMAIN][NAME][CONF_NOTIFIERS] = [BAD_NOTIFIER, NOTIFIER] + assert await async_setup_component(hass, DOMAIN, config) + assert len(mock_notifier) == 0 + + hass.states.async_set("sensor.test", STATE_ON) + await hass.async_block_till_done() + assert len(mock_notifier) == 1 + assert hass.states.get(ENTITY_ID).state == STATE_ON + + hass.states.async_set("sensor.test", STATE_OFF) + await hass.async_block_till_done() + assert len(mock_notifier) == 2 + assert hass.states.get(ENTITY_ID).state == STATE_IDLE + + async def test_no_notifiers( hass: HomeAssistant, mock_notifier: list[ServiceCall] ) -> None: