Skip to content

Commit

Permalink
Fixed more edge case scenarios for gateway termination and fixed tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
Nekoka.tt committed Sep 16, 2020
1 parent 1e29d91 commit 69432f4
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 7 deletions.
16 changes: 10 additions & 6 deletions hikari/impl/shard.py
Original file line number Diff line number Diff line change
Expand Up @@ -666,14 +666,14 @@ async def _identify(self) -> None:
await self._ws.send_json(payload) # type: ignore[union-attr]

async def _heartbeat(self, heartbeat_interval: float) -> bool:
# Return True if zombied.
# Return True if zombied or should reconnect, false if time to die forever.
# Prevent immediately zombie-ing.
self._last_heartbeat_ack_received = date.monotonic()
self._logger.debug("starting heartbeat with interval %ss", heartbeat_interval)

while True:
while not self._closing.is_set() and not self._closed.is_set():
if self._last_heartbeat_ack_received <= self._last_heartbeat_sent:
# Gateway is zombie
# Gateway is zombie, close and request reconnect.
self._logger.warning(
"connection has not received a HEARTBEAT_ACK for approx %.1fs and is being disconnected, "
"expect a reconnect shortly",
Expand All @@ -690,11 +690,14 @@ async def _heartbeat(self, heartbeat_interval: float) -> bool:
try:
await asyncio.wait_for(self._closing.wait(), timeout=heartbeat_interval)
# We are closing
return False
break
except asyncio.TimeoutError:
# We should continue
continue

self._logger.debug("heartbeat task is finishing now")
return False

async def _poll_events(self) -> typing.Optional[bool]:
payload = await self._ws.receive_json(timeout=5) # type: ignore[union-attr]

Expand Down Expand Up @@ -742,6 +745,7 @@ async def _resume(self) -> None:

async def _run(self) -> None:
self._closed.clear()
self._closing.clear()
last_started_at = -float("inf")

backoff = rate_limits.ExponentialBackOff(
Expand All @@ -751,7 +755,7 @@ async def _run(self) -> None:
)

try:
while not self._closing.is_set() and not self._closed:
while not self._closing.is_set() and not self._closed.is_set():
if date.monotonic() - last_started_at < _BACKOFF_WINDOW:
time = next(backoff)
self._logger.info("backing off reconnecting for %.2fs", time)
Expand Down Expand Up @@ -801,10 +805,10 @@ async def _run(self) -> None:
self._logger.error("encountered some unhandled error", exc_info=ex)
raise
finally:
self._closing.set()
self._closed.set()

async def _run_once(self) -> bool:
self._closing.clear()
self._handshake_completed.clear()
dispatch_disconnect = False

Expand Down
3 changes: 2 additions & 1 deletion tests/hikari/impl/test_shard.py
Original file line number Diff line number Diff line change
Expand Up @@ -970,7 +970,8 @@ async def test__identify_when_intents(self, client):
async def test__heartbeat(self, client):
client._last_heartbeat_sent = 5
client._logger = mock.Mock()
client._closing = mock.Mock()
client._closing = mock.Mock(is_set=mock.Mock(return_value=False))
client._closed = mock.Mock(is_set=mock.Mock(return_value=False))
client._send_heartbeat = mock.AsyncMock()

with mock.patch.object(date, "monotonic", return_value=10):
Expand Down

0 comments on commit 69432f4

Please sign in to comment.