Skip to content

Commit d29ee75

Browse files
authored
Retry once on remote protocol errors (#80)
1 parent 42ae076 commit d29ee75

File tree

2 files changed

+21
-3
lines changed

2 files changed

+21
-3
lines changed

onvif/client.py

+19-2
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,23 @@ def original_load(self, *args: Any, **kwargs: Any) -> None:
9696
return original_load(self, *args, **kwargs)
9797

9898

99+
class AsyncTransportProtocolErrorHandler(AsyncTransport):
100+
"""Retry on remote protocol error.
101+
102+
http://datatracker.ietf.org/doc/html/rfc2616#section-8.1.4 allows the server
103+
# to close the connection at any time, we treat this as a normal and try again
104+
# once since
105+
"""
106+
107+
@retry_connection_error(attempts=2, exception=httpx.RemoteProtocolError)
108+
async def post(self, address, message, headers):
109+
return await super().post(address, message, headers)
110+
111+
@retry_connection_error(attempts=2, exception=httpx.RemoteProtocolError)
112+
async def get(self, address, params, headers):
113+
return await super().get(address, params, headers)
114+
115+
99116
async def _cached_document(url: str) -> Document:
100117
"""Load external XML document from disk."""
101118
if url in _DOCUMENT_CACHE:
@@ -223,9 +240,9 @@ def __init__(
223240
verify=_NO_VERIFY_SSL_CONTEXT, timeout=timeouts, limits=_HTTPX_LIMITS
224241
)
225242
self.transport = (
226-
AsyncTransport(client=client, wsdl_client=wsdl_client)
243+
AsyncTransportProtocolErrorHandler(client=client, wsdl_client=wsdl_client)
227244
if no_cache
228-
else AsyncTransport(
245+
else AsyncTransportProtocolErrorHandler(
229246
client=client, wsdl_client=wsdl_client, cache=SqliteCache()
230247
)
231248
)

onvif/wrappers.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
def retry_connection_error(
2121
attempts: int = DEFAULT_ATTEMPTS,
22+
exception: httpx.HTTPError = httpx.RequestError,
2223
) -> Callable[[Callable[P, Awaitable[T]]], Callable[P, Awaitable[T]]]:
2324
"""Define a wrapper to retry on connection error."""
2425

@@ -37,7 +38,7 @@ async def _async_wrap_connection_error_retry( # type: ignore[return]
3738
for attempt in range(attempts):
3839
try:
3940
return await func(*args, **kwargs)
40-
except httpx.RequestError as ex:
41+
except exception as ex:
4142
#
4243
# We should only need to retry on RemoteProtocolError but some cameras
4344
# are flakey and sometimes do not respond to the Renew request so we

0 commit comments

Comments
 (0)