Fix memory leak in onvif (#83006)

fixes https://github.com/home-assistant/core/issues/82504
This commit is contained in:
J. Nick Koston 2022-11-30 10:40:59 -10:00 committed by GitHub
parent 532ab12a48
commit 4239923ea2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 13 deletions

View File

@ -11,7 +11,7 @@ from httpx import RequestError
import onvif import onvif
from onvif import ONVIFCamera from onvif import ONVIFCamera
from onvif.exceptions import ONVIFError from onvif.exceptions import ONVIFError
from zeep.exceptions import Fault from zeep.exceptions import Fault, XMLParseError
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
@ -284,7 +284,7 @@ class ONVIFDevice:
snapshot = media_capabilities and media_capabilities.SnapshotUri snapshot = media_capabilities and media_capabilities.SnapshotUri
pullpoint = False pullpoint = False
with suppress(ONVIFError, Fault, RequestError): with suppress(ONVIFError, Fault, RequestError, XMLParseError):
pullpoint = await self.events.async_start() pullpoint = await self.events.async_start()
ptz = False ptz = False

View File

@ -5,6 +5,7 @@ import asyncio
from collections.abc import Callable from collections.abc import Callable
from contextlib import suppress from contextlib import suppress
import datetime as dt import datetime as dt
from logging import DEBUG, WARNING
from httpx import RemoteProtocolError, TransportError from httpx import RemoteProtocolError, TransportError
from onvif import ONVIFCamera, ONVIFService from onvif import ONVIFCamera, ONVIFService
@ -20,7 +21,6 @@ from .parsers import PARSERS
UNHANDLED_TOPICS = set() UNHANDLED_TOPICS = set()
SUBSCRIPTION_ERRORS = ( SUBSCRIPTION_ERRORS = (
XMLParseError,
Fault, Fault,
asyncio.TimeoutError, asyncio.TimeoutError,
TransportError, TransportError,
@ -122,20 +122,32 @@ class EventManager:
if self._subscription: if self._subscription:
# Suppressed. The subscription may no longer exist. # Suppressed. The subscription may no longer exist.
with suppress(*SUBSCRIPTION_ERRORS): try:
await self._subscription.Unsubscribe() await self._subscription.Unsubscribe()
except (XMLParseError, *SUBSCRIPTION_ERRORS) as err:
LOGGER.debug(
"Failed to unsubscribe ONVIF PullPoint subscription for '%s';"
" This is normal if the device restarted: %s",
self.unique_id,
err,
)
self._subscription = None self._subscription = None
try: try:
restarted = await self.async_start() restarted = await self.async_start()
except SUBSCRIPTION_ERRORS: except (XMLParseError, *SUBSCRIPTION_ERRORS) as err:
restarted = False restarted = False
# Device may not support subscriptions so log at debug level
# when we get an XMLParseError
LOGGER.log(
DEBUG if isinstance(err, XMLParseError) else WARNING,
"Failed to restart ONVIF PullPoint subscription for '%s'; "
"Retrying later: %s",
self.unique_id,
err,
)
if not restarted: if not restarted:
LOGGER.warning(
"Failed to restart ONVIF PullPoint subscription for '%s'. Retrying",
self.unique_id,
)
# Try again in a minute # Try again in a minute
self._unsub_refresh = async_call_later(self.hass, 60, self.async_restart) self._unsub_refresh = async_call_later(self.hass, 60, self.async_restart)
elif self._listeners: elif self._listeners:
@ -154,8 +166,7 @@ class EventManager:
.isoformat(timespec="seconds") .isoformat(timespec="seconds")
.replace("+00:00", "Z") .replace("+00:00", "Z")
) )
with suppress(*SUBSCRIPTION_ERRORS): await self._subscription.Renew(termination_time)
await self._subscription.Renew(termination_time)
def async_schedule_pull(self) -> None: def async_schedule_pull(self) -> None:
"""Schedule async_pull_messages to run.""" """Schedule async_pull_messages to run."""
@ -178,8 +189,11 @@ class EventManager:
except RemoteProtocolError: except RemoteProtocolError:
# Likely a shutdown event, nothing to see here # Likely a shutdown event, nothing to see here
return return
except SUBSCRIPTION_ERRORS as err: except (XMLParseError, *SUBSCRIPTION_ERRORS) as err:
LOGGER.warning( # Device may not support subscriptions so log at debug level
# when we get an XMLParseError
LOGGER.log(
DEBUG if isinstance(err, XMLParseError) else WARNING,
"Failed to fetch ONVIF PullPoint subscription messages for '%s': %s", "Failed to fetch ONVIF PullPoint subscription messages for '%s': %s",
self.unique_id, self.unique_id,
err, err,