From c754995519e44ca16c9d812bc311b05344f282b1 Mon Sep 17 00:00:00 2001 From: Alexandra Szanto Date: Thu, 12 Nov 2026 12:59:40 +0100 Subject: [PATCH] fix: do not raise an error because of a broken trasport --- UnleashClient/api_client/_async.py | 56 ++++++++--------- UnleashClient/api_client/_sync.py | 61 +++++++++---------- .../test_async_unleash_api_client.py | 8 +++ tests/unit_tests/test_unleash_api_client.py | 7 +++ 4 files changed, 73 insertions(+), 59 deletions(-) diff --git a/UnleashClient/api_client/_async.py b/UnleashClient/api_client/_async.py index 87d4a73c..9b0bd400 100644 --- a/UnleashClient/api_client/_async.py +++ b/UnleashClient/api_client/_async.py @@ -164,8 +164,8 @@ async def register(self, payload: Dict[str, Any]) -> bool: Register this client with the server. Returns True on 200 or 202, False on any other status and when the - request fails: any exception from the transport is logged and reported - as False. + request fails: an exception from the transport, or a response the SDK + can't read, is logged and reported as False. :param payload: as built by :func:`UnleashClient._payloads._build_register_payload`. @@ -185,30 +185,30 @@ async def register(self, payload: Dict[str, Any]) -> bool: ) try: resp = await self._transport.execute(request) + + if resp.status not in {200, 202}: + _log_resp_info(resp) + LOGGER.warning( + "Unleash Client registration failed due to unexpected HTTP status code: %s", + resp.status, + ) + return False + + LOGGER.info("Unleash Client successfully registered!") + + return True except Exception as exc: # pylint: disable=broad-except LOGGER.exception( "Unleash Client registration failed due to exception: %s", exc ) return False - if resp.status not in {200, 202}: - _log_resp_info(resp) - LOGGER.warning( - "Unleash Client registration failed due to unexpected HTTP status code: %s", - resp.status, - ) - return False - - LOGGER.info("Unleash Client successfully registered!") - - return True - async def send_metrics(self, payload: Dict[str, Any]) -> bool: """ Send one metrics bucket. - Returns True only on 202. Every other status and any exception from the - transport return False. + Returns True only on 202. Every other status, an exception from the + transport and a response the SDK can't read return False. :param payload: the metrics request body. :raises AlreadyClosedError: if the API client has been closed. @@ -228,6 +228,18 @@ async def send_metrics(self, payload: Dict[str, Any]) -> bool: ) try: resp = await self._transport.execute(request) + + if resp.status != 202: + _log_resp_info(resp) + LOGGER.warning( + "Unleash Client metrics submission due to unexpected HTTP status code: %s", + resp.status, + ) + return False + + LOGGER.info("Unleash Client metrics successfully sent!") + + return True except asyncio.CancelledError: LOGGER.warning("Unleash Client metrics submission was cancelled.") raise @@ -239,15 +251,3 @@ async def send_metrics(self, payload: Dict[str, Any]) -> bool: "Unleash Client metrics submission failed due to exception: %s", exc ) return False - - if resp.status != 202: - _log_resp_info(resp) - LOGGER.warning( - "Unleash Client metrics submission due to unexpected HTTP status code: %s", - resp.status, - ) - return False - - LOGGER.info("Unleash Client metrics successfully sent!") - - return True diff --git a/UnleashClient/api_client/_sync.py b/UnleashClient/api_client/_sync.py index 241f66b2..0e97b40f 100644 --- a/UnleashClient/api_client/_sync.py +++ b/UnleashClient/api_client/_sync.py @@ -138,12 +138,12 @@ def register(self, payload: Dict[str, Any]) -> bool: """ Register this client with the Unleash server. - Any exception from the transport is a failed request: it is logged and - False is returned. + Never raises for a failed request: an exception from the transport, or + a response the SDK can't read, is logged and False is returned. :param payload: Registration request body. - :return: True on 200 or 202; False on any other status and on a request - error. + :return: True on 200 or 202; False on any other status, on a request + error and on a response the SDK can't read. """ config = self._config LOGGER.info("Registering unleash client with unleash @ %s", config.url) @@ -157,33 +157,33 @@ def register(self, payload: Dict[str, Any]) -> bool: ) try: resp = self._transport.execute(request) + if resp.status not in {200, 202}: + _log_resp_info(resp) + LOGGER.warning( + "Unleash Client registration failed due to unexpected HTTP status code: %s", + resp.status, + ) + return False + + LOGGER.info("Unleash Client successfully registered!") + + return True except Exception as exc: # pylint: disable=broad-except LOGGER.exception( "Unleash Client registration failed due to exception: %s", exc ) return False - if resp.status not in {200, 202}: - _log_resp_info(resp) - LOGGER.warning( - "Unleash Client registration failed due to unexpected HTTP status code: %s", - resp.status, - ) - return False - - LOGGER.info("Unleash Client successfully registered!") - - return True - def send_metrics(self, payload: Dict[str, Any]) -> bool: """ Send one metrics bucket to the Unleash server. - Any exception from the transport is a failed request: it is logged and - False is returned. + Never raises for a failed request: an exception from the transport, or + a response the SDK can't read, is logged and False is returned. :param payload: Metrics request body. - :return: True on 202; False on any other status and on a request error. + :return: True on 202; False on any other status, on a request error and + on a response the SDK can't read. """ config = self._config LOGGER.info("Sending messages to with unleash @ %s", config.url) @@ -197,20 +197,19 @@ def send_metrics(self, payload: Dict[str, Any]) -> bool: ) try: resp = self._transport.execute(request) + if resp.status != 202: + _log_resp_info(resp) + LOGGER.warning( + "Unleash Client metrics submission due to unexpected HTTP status code: %s", + resp.status, + ) + return False + + LOGGER.info("Unleash Client metrics successfully sent!") + + return True except Exception as exc: # pylint: disable=broad-except LOGGER.warning( "Unleash Client metrics submission failed due to exception: %s", exc ) return False - - if resp.status != 202: - _log_resp_info(resp) - LOGGER.warning( - "Unleash Client metrics submission due to unexpected HTTP status code: %s", - resp.status, - ) - return False - - LOGGER.info("Unleash Client metrics successfully sent!") - - return True diff --git a/tests/unit_tests/test_async_unleash_api_client.py b/tests/unit_tests/test_async_unleash_api_client.py index 8ce1826d..15210883 100644 --- a/tests/unit_tests/test_async_unleash_api_client.py +++ b/tests/unit_tests/test_async_unleash_api_client.py @@ -627,6 +627,14 @@ async def test_any_transport_exception_is_a_failed_request(exc): assert await api_client.send_metrics(MOCK_METRICS_REQUEST) is False +@mark.asyncio +async def test_register_and_send_metrics_never_raise_on_a_broken_response(): + api_client = api_client_over(RecordingTransport(object())) + + assert await api_client.register({}) is False + assert await api_client.send_metrics({}) is False + + @mark.asyncio async def test_a_transport_closed_by_its_creator_gives_failed_requests(): transport = AiohttpTransport() diff --git a/tests/unit_tests/test_unleash_api_client.py b/tests/unit_tests/test_unleash_api_client.py index 4c94681d..e71ed0d4 100644 --- a/tests/unit_tests/test_unleash_api_client.py +++ b/tests/unit_tests/test_unleash_api_client.py @@ -461,6 +461,13 @@ def test_any_transport_exception_is_a_failed_request(exc): assert api_client.send_metrics({}) is False +def test_register_and_send_metrics_never_raise_on_a_broken_response(): + api_client = api_client_over(RecordingTransport(object())) + + assert api_client.register({}) is False + assert api_client.send_metrics({}) is False + + @mark.parametrize( "call", (