Skip to content

Commit 1e1b255

Browse files
committed
Log disconnect and reconnect once.
1 parent 6d0ba3b commit 1e1b255

File tree

2 files changed

+43
-16
lines changed

2 files changed

+43
-16
lines changed

pyplumio/connection.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,12 @@ class Connection(ABC, TaskManager):
3737
All specific connection classes MUST be inherited from this class.
3838
"""
3939

40-
__slots__ = ("_protocol", "_reconnect_on_failure", "_options")
40+
__slots__ = ("_protocol", "_reconnect_on_failure", "_options", "_retries")
4141

4242
_protocol: Protocol
4343
_reconnect_on_failure: bool
4444
_options: dict[str, Any]
45+
_retries: int
4546

4647
def __init__(
4748
self,
@@ -60,6 +61,7 @@ def __init__(
6061
self._reconnect_on_failure = reconnect_on_failure
6162
self._protocol = protocol
6263
self._options = options
64+
self._retries = 0
6365

6466
async def __aenter__(self) -> Connection:
6567
"""Provide an entry point for the context manager."""
@@ -86,11 +88,21 @@ async def _reconnect(self) -> None:
8688
"""Try to connect and reconnect on failure."""
8789
try:
8890
await self._connect()
91+
if self._retries > 0:
92+
_LOGGER.info(
93+
"Connection to device restored after %i retries", self._retries
94+
)
95+
self._retries = 0
8996
except ConnectionFailedError:
90-
_LOGGER.error(
91-
"Can't connect to the device, retrying in %.1f seconds",
92-
RECONNECT_AFTER_SECONDS,
93-
)
97+
if self._retries == 0:
98+
_LOGGER.error(
99+
(
100+
"Unable to connect to the device. Connection we be retried "
101+
"automatically every %i seconds in background."
102+
),
103+
RECONNECT_AFTER_SECONDS,
104+
)
105+
self._retries += 1
94106
await asyncio.sleep(RECONNECT_AFTER_SECONDS)
95107
self.create_task(self._reconnect(), name="reconnect_task")
96108

tests/test_connection.py

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@
1313
from serial import EIGHTBITS, PARITY_NONE, STOPBITS_ONE
1414

1515
import pyplumio.connection
16-
from pyplumio.connection import Connection, SerialConnection, TcpConnection
16+
from pyplumio.connection import (
17+
RECONNECT_AFTER_SECONDS,
18+
Connection,
19+
SerialConnection,
20+
TcpConnection,
21+
)
1722
from pyplumio.devices.ecomax import EcoMAX
1823
from pyplumio.exceptions import ConnectionFailedError
1924
from pyplumio.protocol import AsyncProtocol, DummyProtocol, Protocol
@@ -115,33 +120,43 @@ async def test_connect(self, mock_open_connection, mock_protocol) -> None:
115120
await connection.close()
116121
mock_protocol.shutdown.assert_called_once()
117122

118-
@pytest.mark.parametrize(
119-
("reconnect_on_failure", "expected_log"),
120-
[
121-
(True, "Can't connect to the device"),
122-
(False, None),
123-
],
123+
@pytest.mark.parametrize("reconnect_on_failure", [True, False])
124+
@patch.object(
125+
DummyConnection,
126+
"_open_connection",
127+
side_effect=(OSError, (AsyncMock(), AsyncMock), None),
124128
)
125-
@patch.object(DummyConnection, "_open_connection", side_effect=(OSError, None))
129+
@patch("pyplumio.protocol.AsyncProtocol.connection_established")
126130
async def test_reconnect(
127131
self,
132+
mock_connection_established,
128133
mock_open_connection,
129134
caplog,
130135
reconnect_on_failure: bool,
131-
expected_log: str | None,
132136
) -> None:
133137
"""Test reconnect logic."""
134138
connection = DummyConnection(reconnect_on_failure=reconnect_on_failure)
135139
if reconnect_on_failure:
136140
with caplog.at_level(logging.ERROR):
137141
await connection.connect()
142+
assert "Unable to connect to the device." in caplog.text
143+
assert (
144+
f"Will attempt to reconnect every {RECONNECT_AFTER_SECONDS} seconds"
145+
in caplog.text
146+
)
147+
148+
with caplog.at_level(logging.INFO):
149+
await connection.connect()
150+
assert "Connection to device restored after 1 retries" in caplog.text
151+
mock_connection_established.assert_called_once()
152+
153+
assert mock_open_connection.await_count == 2
138154

139-
assert expected_log in caplog.text
140155
else:
141156
with pytest.raises(ConnectionFailedError):
142157
await connection.connect()
143158

144-
mock_open_connection.assert_awaited_once()
159+
mock_open_connection.assert_awaited_once()
145160

146161
@patch.object(DummyConnection, "close")
147162
@patch.object(DummyConnection, "connect")

0 commit comments

Comments
 (0)