From 2bd832cd7afa7e48bf4d0fce4d46cef3addbbda1 Mon Sep 17 00:00:00 2001 From: Jc2k Date: Sun, 18 Aug 2019 05:14:46 +0100 Subject: [PATCH] Skip homekit_controller polls when system is overloaded and still trying to process the previous one (#25968) * Skip async_update if there are signs of backpressure * Black * Only warn once * Log on recovery * Formatting fix --- .../homekit_controller/connection.py | 49 +++++++++++++------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/homekit_controller/connection.py b/homeassistant/components/homekit_controller/connection.py index 8068f26aaa3..1cb2131fb8f 100644 --- a/homeassistant/components/homekit_controller/connection.py +++ b/homeassistant/components/homekit_controller/connection.py @@ -103,6 +103,10 @@ class HKDevice: # this method. self._polling_interval_remover = None + # Never allow concurrent polling of the same accessory or bridge + self._polling_lock = asyncio.Lock() + self._polling_lock_warned = False + def add_pollable_characteristics(self, characteristics): """Add (aid, iid) pairs that we need to poll.""" self.pollable_characteristics.extend(characteristics) @@ -247,25 +251,40 @@ class HKDevice: _LOGGER.debug("HomeKit connection not polling any characteristics.") return - _LOGGER.debug("Starting HomeKit controller update") + if self._polling_lock.locked(): + if not self._polling_lock_warned: + _LOGGER.warning( + "HomeKit controller update skipped as previous poll still in flight" + ) + self._polling_lock_warned = True + return - try: - new_values_dict = await self.get_characteristics( - self.pollable_characteristics + if self._polling_lock_warned: + _LOGGER.info( + "HomeKit controller no longer detecting back pressure - not skipping poll" ) - except AccessoryNotFoundError: - # Not only did the connection fail, but also the accessory is not - # visible on the network. - self.async_set_unavailable() - return - except (AccessoryDisconnectedError, EncryptionError): - # Temporary connection failure. Device is still available but our - # connection was dropped. - return + self._polling_lock_warned = False - self.process_new_events(new_values_dict) + async with self._polling_lock: + _LOGGER.debug("Starting HomeKit controller update") - _LOGGER.debug("Finished HomeKit controller update") + try: + new_values_dict = await self.get_characteristics( + self.pollable_characteristics + ) + except AccessoryNotFoundError: + # Not only did the connection fail, but also the accessory is not + # visible on the network. + self.async_set_unavailable() + return + except (AccessoryDisconnectedError, EncryptionError): + # Temporary connection failure. Device is still available but our + # connection was dropped. + return + + self.process_new_events(new_values_dict) + + _LOGGER.debug("Finished HomeKit controller update") def process_new_events(self, new_values_dict): """Process events from accessory into HA state."""