Skip to content

Commit

Permalink
fix: Let wait_for_ecu() reconnect on all ConnectionErrors incl. hidden
Browse files Browse the repository at this point in the history
Currently, a broken transport triggers a reconnect in request_unsafe(),
but only in case of retries. Since wait_for_ecu specifically sets
retries to 0 this is not happening and instead ConnectionErrors are
transformed to UDSExceptions.
This commit brings two major changes:

1. `request_unsafe` sets the __cause__ of the MissingResponse to
   ConnectionError to provide callers with additional information
2. `wait_for_ecu` treats a MissingRespone caused by a ConnectionError
   the same as a ConnectionError and calls reconnect
  • Loading branch information
ferdinandjarisch committed Feb 4, 2025
1 parent 02190ee commit 1ac3519
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 4 deletions.
3 changes: 3 additions & 0 deletions src/gallia/services/uds/core/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ async def request_unsafe(
except ConnectionError as e:
logger.warning(f"{request} failed with: {e!r}")
last_exception = MissingResponse(request, str(e))
# Explicitly set __cause__ such that higher levels might react, e.g. wait_for_ecu()
# Basically equal to "raise last_exception from e"
last_exception.__cause__ = e
if i < max_retry:
logger.info(f"Sleeping for {wait_time}s before attempting to reconnect")
await asyncio.sleep(wait_time)
Expand Down
13 changes: 9 additions & 4 deletions src/gallia/services/uds/ecu.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,11 +323,16 @@ async def _wait_for_ecu_endless_loop(self, sleep_time: float) -> None:
await asyncio.sleep(sleep_time)
await self.ping(config=config)
break
except ConnectionError as e:
logger.debug(f"ECU not ready: {e!r}, reconnecting…")
await self.reconnect()
except UDSException as e:
# When the ECU is not ready, we expect an UDSException, e.g. MissingResponse.
# On ConnectionError, we additionally reconnect the transport to ensure connectivity.
# Since Gallia converts a ConnectionError to a MissingResponse in `request_unsafe`, however,
# there is a need to reconnect the transport also in case of high-level UDSExceptions
# such as MissingResponses that are raised (__cause__) from ConnectionErrors.
except (ConnectionError, UDSException) as e:
logger.debug(f"ECU not ready: {e!r}")
if isinstance(e, ConnectionError) or isinstance(e.__cause__, ConnectionError):
logger.debug("Reconnecting…")
await self.reconnect()
logger.info("ECU ready")

async def wait_for_ecu(
Expand Down

0 comments on commit 1ac3519

Please sign in to comment.