…twork outages
Bug 1: Replace bare asyncio.sleep(cur_interval) with an event-aware
asyncio.wait_for(stop_event.wait(), timeout=cur_interval) so that the
backoff sleep is interrupted immediately when the stop_event is set.
Previously, a bot experiencing a network outage could hang for up to
30 seconds on graceful shutdown while the backoff sleep ran uninterrupted.
Bug 2: After calling .cancel() on pending asyncio tasks inside do_action(),
await asyncio.gather(*pending, return_exceptions=True) to ensure cancelled
tasks are fully cleaned up before returning. Without this, merely requesting
cancellation left tasks in a pending state, causing 'Task was destroyed but
it is pending!' warnings from the garbage collector when the tasks were
eventually collected.
Summary
Fixes three related bugs in networkloop.py caused by stop_event being partially ignored during shutdown:
Adds three regression tests to prevent recurrence.
Tests
Results:
Live verification:
Ran a custom asyncio verification script locally simulating network outages. Confirmed the event loop exits promptly on shutdown and no pending task warnings are emitted during teardown.