提交 231b7fd5 编写于 作者: P Pierre Fersing

Add exponential reconnection delay

上级 cbf1da91
...@@ -14,6 +14,7 @@ v1.3.x - 2017-xx-xx ...@@ -14,6 +14,7 @@ v1.3.x - 2017-xx-xx
- Allow arbitrary Websocket headers and path. - Allow arbitrary Websocket headers and path.
Closes #169. Closes #169.
- Fix issue with large inbound payload over Websocket. Closes #107. - Fix issue with large inbound payload over Websocket. Closes #107.
- Add exponential delay for reconnection. Closes #195.
- Move unit tests to pytest (#164) and tox (#187) - Move unit tests to pytest (#164) and tox (#187)
- Add support for standard Python logging. Closes #95. - Add support for standard Python logging. Closes #95.
......
...@@ -383,6 +383,23 @@ retain ...@@ -383,6 +383,23 @@ retain
Raises a ``ValueError`` if ``qos`` is not 0, 1 or 2, or if ``topic`` is Raises a ``ValueError`` if ``qos`` is not 0, 1 or 2, or if ``topic`` is
``None`` or has zero string length. ``None`` or has zero string length.
reconnect_delay_set
'''''''''''''''''''
::
reconnect_delay_set(min_delay=1, max_delay=120)
The client will automatically retry connection. Between each attempt
it will wait a number of seconds between ``min_delay`` and ``max_delay``.
When the connection is lost, initially the reconnection attempt is delayed of
``min_delay`` seconds. It's doubled between subsequent attempt up to ``max_delay``.
The delay is reset to ``min_delay`` when the connection complete (e.g. the CONNACK is
received, not just the TCP connection is established).
Connect / reconnect / disconnect Connect / reconnect / disconnect
```````````````````````````````` ````````````````````````````````
......
...@@ -516,6 +516,9 @@ class Client(object): ...@@ -516,6 +516,9 @@ class Client(object):
self._current_out_packet = None self._current_out_packet = None
self._last_msg_in = time_func() self._last_msg_in = time_func()
self._last_msg_out = time_func() self._last_msg_out = time_func()
self._reconnect_min_delay = 1
self._reconnect_max_delay = 120
self._reconnect_delay = None
self._ping_t = 0 self._ping_t = 0
self._last_mid = 0 self._last_mid = 0
self._state = mqtt_cs_new self._state = mqtt_cs_new
...@@ -541,6 +544,7 @@ class Client(object): ...@@ -541,6 +544,7 @@ class Client(object):
self._msgtime_mutex = threading.Lock() self._msgtime_mutex = threading.Lock()
self._out_message_mutex = threading.RLock() self._out_message_mutex = threading.RLock()
self._in_message_mutex = threading.Lock() self._in_message_mutex = threading.Lock()
self._reconnect_delay_mutex = threading.Lock()
self._thread = None self._thread = None
self._thread_terminate = False self._thread_terminate = False
self._ssl = False self._ssl = False
...@@ -814,6 +818,19 @@ class Client(object): ...@@ -814,6 +818,19 @@ class Client(object):
self._state = mqtt_cs_connect_async self._state = mqtt_cs_connect_async
def reconnect_delay_set(self, min_delay=1, max_delay=120):
""" Configure the exponential reconnect delay
When connection is lost, wait initially min_delay seconds and
double this time every attempt. The wait is capped at max_delay.
Once the client is fully connected (e.g. not only TCP socket, but
received a success CONNACK), the wait timer is reset to min_delay.
"""
with self._reconnect_delay_mutex:
self._reconnect_min_delay = min_delay
self._reconnect_max_delay = min_delay
self._reconnect_delay = None
def reconnect(self): def reconnect(self):
"""Reconnect the client after a disconnect. Can only be called after """Reconnect the client after a disconnect. Can only be called after
connect()/connect_async().""" connect()/connect_async()."""
...@@ -1433,7 +1450,7 @@ class Client(object): ...@@ -1433,7 +1450,7 @@ class Client(object):
if not retry_first_connection: if not retry_first_connection:
raise raise
self._easy_log(MQTT_LOG_DEBUG, "Connection failed, retrying") self._easy_log(MQTT_LOG_DEBUG, "Connection failed, retrying")
time.sleep(1) self._reconnect_wait()
else: else:
break break
...@@ -1460,7 +1477,7 @@ class Client(object): ...@@ -1460,7 +1477,7 @@ class Client(object):
if should_exit(): if should_exit():
run = False run = False
else: else:
time.sleep(1) self._reconnect_wait()
if should_exit(): if should_exit():
run = False run = False
...@@ -2310,6 +2327,7 @@ class Client(object): ...@@ -2310,6 +2327,7 @@ class Client(object):
if result == 0: if result == 0:
self._state = mqtt_cs_connected self._state = mqtt_cs_connected
self._reconnect_delay = None
self._easy_log(MQTT_LOG_DEBUG, "Received CONNACK (%s, %s)", flags, result) self._easy_log(MQTT_LOG_DEBUG, "Received CONNACK (%s, %s)", flags, result)
...@@ -2585,6 +2603,28 @@ class Client(object): ...@@ -2585,6 +2603,28 @@ class Client(object):
def _thread_main(self): def _thread_main(self):
self.loop_forever(retry_first_connection=True) self.loop_forever(retry_first_connection=True)
def _reconnect_wait(self):
# See reconnect_delay_set for details
now = time_func()
with self._reconnect_delay_mutex:
if self._reconnect_delay is None:
self._reconnect_delay = self._reconnect_min_delay
else:
self._reconnect_delay = min(
self._reconnect_delay * 2,
self._reconnect_max_delay,
)
target_time = now + self._reconnect_delay
remaining = target_time - now
while (self._state != mqtt_cs_disconnecting
and not self._thread_terminate
and remaining > 0):
time.sleep(min(remaining, 1))
remaining = target_time - time_func()
# Compatibility class for easy porting from mosquitto.py. # Compatibility class for easy porting from mosquitto.py.
class Mosquitto(Client): class Mosquitto(Client):
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册