Clean up unused Sonos subscriptions (#51583)

This commit is contained in:
jjlawren 2021-06-09 23:31:14 -05:00 committed by GitHub
parent 417ba5538d
commit c362ffd384
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 19 additions and 8 deletions

View File

@ -129,6 +129,10 @@ async def async_setup_entry( # noqa: C901
pysonos.config.EVENT_ADVERTISE_IP = advertise_addr pysonos.config.EVENT_ADVERTISE_IP = advertise_addr
async def _async_stop_event_listener(event: Event) -> None: async def _async_stop_event_listener(event: Event) -> None:
await asyncio.gather(
*[speaker.async_unsubscribe() for speaker in data.discovered.values()],
return_exceptions=True,
)
if events_asyncio.event_listener: if events_asyncio.event_listener:
await events_asyncio.event_listener.async_stop() await events_asyncio.event_listener.async_stop()

View File

@ -64,13 +64,14 @@ class SonosEntity(Entity):
async def async_poll(self, now: datetime.datetime) -> None: async def async_poll(self, now: datetime.datetime) -> None:
"""Poll the entity if subscriptions fail.""" """Poll the entity if subscriptions fail."""
if self.speaker.is_first_poll: if not self.speaker.subscriptions_failed:
_LOGGER.warning( _LOGGER.warning(
"%s cannot reach [%s], falling back to polling, functionality may be limited", "%s cannot reach [%s], falling back to polling, functionality may be limited",
self.speaker.zone_name, self.speaker.zone_name,
self.speaker.subscription_address, self.speaker.subscription_address,
) )
self.speaker.is_first_poll = False self.speaker.subscriptions_failed = True
await self.speaker.async_unsubscribe()
try: try:
await self.async_update() # pylint: disable=no-member await self.async_update() # pylint: disable=no-member
except (OSError, SoCoException) as ex: except (OSError, SoCoException) as ex:

View File

@ -149,11 +149,11 @@ class SonosSpeaker:
self.media = SonosMedia(soco) self.media = SonosMedia(soco)
# Synchronization helpers # Synchronization helpers
self.is_first_poll: bool = True
self._is_ready: bool = False self._is_ready: bool = False
self._platforms_ready: set[str] = set() self._platforms_ready: set[str] = set()
# Subscriptions and events # Subscriptions and events
self.subscriptions_failed: bool = False
self._subscriptions: list[SubscriptionBase] = [] self._subscriptions: list[SubscriptionBase] = []
self._resubscription_lock: asyncio.Lock | None = None self._resubscription_lock: asyncio.Lock | None = None
self._event_dispatchers: dict[str, Callable] = {} self._event_dispatchers: dict[str, Callable] = {}
@ -331,6 +331,15 @@ class SonosSpeaker:
subscription.auto_renew_fail = self.async_renew_failed subscription.auto_renew_fail = self.async_renew_failed
self._subscriptions.append(subscription) self._subscriptions.append(subscription)
async def async_unsubscribe(self) -> None:
"""Cancel all subscriptions."""
_LOGGER.debug("Unsubscribing from events for %s", self.zone_name)
await asyncio.gather(
*[subscription.unsubscribe() for subscription in self._subscriptions],
return_exceptions=True,
)
self._subscriptions = []
@callback @callback
def async_renew_failed(self, exception: Exception) -> None: def async_renew_failed(self, exception: Exception) -> None:
"""Handle a failed subscription renewal.""" """Handle a failed subscription renewal."""
@ -445,7 +454,7 @@ class SonosSpeaker:
SCAN_INTERVAL, SCAN_INTERVAL,
) )
if self._is_ready: if self._is_ready and not self.subscriptions_failed:
done = await self.async_subscribe() done = await self.async_subscribe()
if not done: if not done:
assert self._seen_timer is not None assert self._seen_timer is not None
@ -466,10 +475,7 @@ class SonosSpeaker:
self._poll_timer() self._poll_timer()
self._poll_timer = None self._poll_timer = None
for subscription in self._subscriptions: await self.async_unsubscribe()
await subscription.unsubscribe()
self._subscriptions = []
if not will_reconnect: if not will_reconnect:
self.hass.data[DATA_SONOS].ssdp_known.remove(self.soco.uid) self.hass.data[DATA_SONOS].ssdp_known.remove(self.soco.uid)