xrpl-py
xrpl-py copied to clipboard
Async Client Doesn't Handle Internet Disconnection
Description
It seems like the xrpl.py async client doesn't handle wifi disconnections:
def is_open(self: WebsocketBase) -> bool:
"""
Returns whether the client is currently open.
Returns:
True if the client is currently open, False otherwise.
"""
return (
self._handler_task is not None
and self._messages is not None
and self._websocket is not None
and self._websocket.open
)
This is the logic it uses to see if a connection is open. Please correct me if im wrong: At first glance it looks correct since it checks self._websocket.open but since we're waiting for data from our peer, the TCP network can't tell the difference between a healthy and a broken connection when the peer isn't sending us any data. So this field never updates and the websocket doesn't close - and in turn I can't attempt to reconnect.
Oddly enough even after reconnecting the wifi the websockets don't reconnect (They only reconnect if I disconnect and reconnect the wifi quickly ~2s).
Reproduction
You can just paste the following code in a python file and run it (you need the imports). After youre seeing logs disconnect the wifi and wait about a minute, then reconnect.
If you don't wait around a minute it'll reconnect on its own, but if you wait for longer it doesnt handle reconnection.
from aiohttp import web, web_app
import logging
from websockets.exceptions import ConnectionClosedError
from xrpl.asyncio.clients import (
AsyncWebsocketClient,
)
from xrpl.models import StreamParameter, Subscribe
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
async def start(app: web_app.Application):
stream_type = StreamParameter.LEDGER
ledger_update_sub_req = Subscribe(
streams = [stream_type]
)
async with AsyncWebsocketClient("wss://s1.ripple.com") as client:
# one time subscription
logger.info("[LedgerCreationDataSource] Sending subscribe request")
await client.send(ledger_update_sub_req)
try:
async for message in client:
logger.info("[LedgerCreationDataSource] received message: " + str(message))
except ConnectionClosedError:
logger.error("[LedgerCreationDataSource] Connection closed - connection closed error")
logger.warning("[LedgerCreationDataSource] Connection closed - server kicked us off")
if __name__ == "__main__":
app = web.Application()
app.on_startup.append(start)
web.run_app(app)