Browse Source

fix #21; introduce exponential backoff delay when reconnecting

pull/34/head
Rossen Georgiev 9 years ago
parent
commit
6a0f61bcd8
  1. 43
      steam/core/cm.py

43
steam/core/cm.py

@ -50,6 +50,7 @@ class CMClient(EventEmitter):
_recv_loop = None
_heartbeat_loop = None
_reconnect_backoff_c = 0
def __init__(self, protocol=0):
self.servers = CMServerList()
@ -98,8 +99,25 @@ class CMClient(EventEmitter):
if not event.is_set():
gevent.spawn(self.disconnect)
def disconnect(self, reconnect=False):
"""Close connection"""
def disconnect(self, reconnect=False, nodelay=False):
"""Close connection
.. note::
When ``reconnect`` is ``True``, the delay before reconnect is determined
by exponential backoff algorithm starting from 0 seconds and up to 31 seconds
:param reconnect: attempt to reconnect
:type reconnect: :class:`bool`
:param nodelay: set to ``True`` to ignore reconnect delay
:type nodelay: :class:`bool`
Event: ``disconnected``
Event: ``reconnect`` instead of ``disconnected`` when going to reconnect
:param delay_seconds: seconds delay before reconnect is attempted
:type delay_seconds: :class:`int`
"""
if not self.connected:
return
@ -114,9 +132,18 @@ class CMClient(EventEmitter):
self._reset_attributes()
if reconnect:
self.emit('reconnect')
gevent.spawn(self.connect)
if nodelay:
delay_seconds = 0
self._reconnect_backoff_c = 0
else:
delay_seconds = 2**self._reconnect_backoff_c - 1
self._reconnect_backoff_c = min(5, self._reconnect_backoff_c + 1)
self.emit('reconnect', delay_seconds)
gevent.spawn_later(delay_seconds, self.connect)
else:
self._reconnect_backoff_c = 0
self.emit('disconnected')
def _reset_attributes(self):
@ -237,6 +264,7 @@ class CMClient(EventEmitter):
msg, = self.wait_event(EMsg.ChannelEncryptResult, timeout=5)
if msg is None:
self.servers.mark_bad(self.current_server_addr)
gevent.spawn(self.disconnect, True)
return
@ -291,9 +319,9 @@ class CMClient(EventEmitter):
):
self.servers.mark_bad(self.current_server_addr)
self.disconnect(True)
return
elif result == EResult.OK:
self._reconnect_backoff_c = 0
logger.debug("Logon completed")
self.steam_id = SteamID(msg.header.steamid)
@ -308,6 +336,9 @@ class CMClient(EventEmitter):
interval = msg.body.out_of_game_heartbeat_seconds
self._heartbeat_loop = gevent.spawn(self._heartbeat, interval)
else:
self.emit("error", EResult(result))
self.disconnect()
def _handle_cm_list(self, msg):
logger.debug("Updating CM list")

Loading…
Cancel
Save