From 187794745db031a530d6f65a3ac2c2a3cb338e94 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Sat, 11 Jun 2022 22:11:44 +0200 Subject: [PATCH] Wrap TCP request reading in `async_timeout.timeout()` There have recently been [reports of `RuntimeError: coroutine ignored GeneratorExit`] which are presumably triggered by timeouts on the socket, without being raised as `TimeoutError`. This case seems to be mitigated by timing out the request after a default of 10 seconds which doesn't give `GeneratorExit` - triggered by something yet unknown - enough time to surface. [reports of `RuntimeError: coroutine ignored GeneratorExit`]: https://github.com/robbinjanssen/home-assistant-omnik-inverter/issues/116 --- omnikinverter/omnikinverter.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/omnikinverter/omnikinverter.py b/omnikinverter/omnikinverter.py index 482f2509..111624b0 100644 --- a/omnikinverter/omnikinverter.py +++ b/omnikinverter/omnikinverter.py @@ -139,20 +139,34 @@ async def tcp_request(self) -> dict[str, Any]: raise OmnikInverterAuthError("serial_number is missing from the request") try: - if self._socket_mock is not None: - reader, writer = await asyncio.open_connection(sock=self._socket_mock) - else: # pragma: no cover - reader, writer = await asyncio.open_connection(self.host, self.tcp_port) + async with async_timeout.timeout(self.request_timeout): + if self._socket_mock is not None: + reader, writer = await asyncio.open_connection( + sock=self._socket_mock + ) + else: # pragma: no cover + reader, writer = await asyncio.open_connection( + self.host, self.tcp_port + ) except OSError as exception: raise OmnikInverterConnectionError( "Failed to open a TCP connection to the Omnik Inverter device" ) from exception + except asyncio.TimeoutError as exception: + raise OmnikInverterConnectionError( + "Timeout occurred while connecting to Omnik Inverter device" + ) from exception try: - writer.write(tcp.create_information_request(self.serial_number)) - await writer.drain() + async with async_timeout.timeout(self.request_timeout): + writer.write(tcp.create_information_request(self.serial_number)) + await writer.drain() - raw_msg = await reader.read(1024) + raw_msg = await reader.read(1024) + except asyncio.TimeoutError as exception: + raise OmnikInverterConnectionError( + "Timeout occurred while connecting to Omnik Inverter device" + ) from exception finally: writer.close() try: