Add heartbeat_timeout to the Client options.

This setting configures how long before a timeout event is emitted
internally and disconnects the websocket. Since some users were
experiencing issues with the gateway not responding, this should help
mitigate the issue for those with poor PCs.
This commit is contained in:
Rapptz 2017-08-08 21:12:04 -04:00
parent ceafae0ab2
commit de65f7309b
4 changed files with 11 additions and 2 deletions

View File

@ -95,6 +95,11 @@ class Client:
A game to start your presence with upon logging on to Discord. A game to start your presence with upon logging on to Discord.
status: Optional[:class:`Status`] status: Optional[:class:`Status`]
A status to start your presence with upon logging on to Discord. A status to start your presence with upon logging on to Discord.
heartbeat_timeout: float
The maximum numbers of seconds before timing out and restarting the
WebSocket in the case of not receiving a HEARTBEAT_ACK. Useful if
processing the initial packets take too long to the point of disconnecting
you. The default timeout is 60 seconds.
Attributes Attributes
----------- -----------

View File

@ -64,10 +64,11 @@ class KeepAliveHandler(threading.Thread):
self._stop_ev = threading.Event() self._stop_ev = threading.Event()
self._last_ack = time.time() self._last_ack = time.time()
self._last_send = time.time() self._last_send = time.time()
self.heartbeat_timeout = ws._max_heartbeat_timeout
def run(self): def run(self):
while not self._stop_ev.wait(self.interval): while not self._stop_ev.wait(self.interval):
if self._last_ack + 2 * self.interval < time.time(): if self._last_ack + self.heartbeat_timeout < time.time():
log.warn("Shard ID %s has stopped responding to the gateway. Closing and restarting." % self.shard_id) log.warn("Shard ID %s has stopped responding to the gateway. Closing and restarting." % self.shard_id)
coro = self.ws.close(1006) coro = self.ws.close(1006)
f = compat.run_coroutine_threadsafe(coro, loop=self.ws.loop) f = compat.run_coroutine_threadsafe(coro, loop=self.ws.loop)
@ -205,6 +206,7 @@ class DiscordWebSocket(websockets.client.WebSocketClientProtocol):
ws.shard_count = client._connection.shard_count ws.shard_count = client._connection.shard_count
ws.session_id = session ws.session_id = session
ws.sequence = sequence ws.sequence = sequence
ws._max_heartbeat_timeout = client._connection.heartbeat_timeout
client._connection._update_references(ws) client._connection._update_references(ws)
@ -590,6 +592,7 @@ class DiscordVoiceWebSocket(websockets.client.WebSocketClientProtocol):
ws = yield from websockets.connect(gateway, loop=client.loop, klass=cls) ws = yield from websockets.connect(gateway, loop=client.loop, klass=cls)
ws.gateway = gateway ws.gateway = gateway
ws._connection = client ws._connection = client
ws._max_heartbeat_timeout = 60.0
if resume: if resume:
yield from ws.resume() yield from ws.resume()

View File

@ -204,6 +204,7 @@ class AutoShardedClient(Client):
ws.gateway = gateway ws.gateway = gateway
ws.shard_id = shard_id ws.shard_id = shard_id
ws.shard_count = self.shard_count ws.shard_count = self.shard_count
ws._max_heartbeat_timeout = self._connection.heartbeat_timeout
try: try:
# OP HELLO # OP HELLO

View File

@ -64,6 +64,7 @@ class ConnectionState:
self.shard_count = None self.shard_count = None
self._ready_task = None self._ready_task = None
self._fetch_offline = options.get('fetch_offline_members', True) self._fetch_offline = options.get('fetch_offline_members', True)
self.heartbeat_timeout = options.get('heartbeat_timeout', 60.0)
self._listeners = [] self._listeners = []
game = options.get('game', None) game = options.get('game', None)
@ -907,7 +908,6 @@ class AutoShardedConnectionState(ConnectionState):
launch.set() launch.set()
yield from asyncio.sleep(2.0 * self.shard_count, loop=self.loop) yield from asyncio.sleep(2.0 * self.shard_count, loop=self.loop)
if self._fetch_offline: if self._fetch_offline:
guilds = sorted(self._ready_state.guilds, key=lambda g: g.shard_id) guilds = sorted(self._ready_state.guilds, key=lambda g: g.shard_id)