hedgedandlevered
hedgedandlevered

Reputation: 2394

Connecting to websocket with async inside async function

I'm connecting to a websocket in an async function, to update a local mysql db

[edit: although only the coinbase websocket is shown here, it was later identified to be the gemini websocket that had the issue, by hitting the v1 instead of v2 websocket]

async def write_websocket_to_sql(exchange, symbol):
    # handle different inputs to get the correct url and subscription message, and error check
    url = wss://ws-feed.exchange.coinbase.com
    subscription_message = {
        "type": "subscribe",
        "product_ids": ["BTCUSD"],
        "channels": ["level2_batch", "heartbeat"]
    }
    async with websockets.connect(url) as ws:
        # Subscribe to the websocket feed
        await ws.send(json.dumps(subscription_message))
        # Receive and process messages from the websocket
        while True:
            print("receiving message for ", ticker_symbol, " on ", exchange, " at ", datetime.datetime.now())
            try:
                message = await ws.recv()
            except websockets.exceptions.ConnectionClosed:
                print("Connection closed, reconnecting...")
                await ws.send(json.dumps(subscription_message))
                continue
            print("message received success!")
            data = json.loads(message)

I'm looking for an explanation as to why the async with websockets.connect(url) as ws: line needs async. await ws.send is going to wait for the response either way

copilot originally added it in, and indeed, when I remove it I get the error

line 453, in write_websocket_to_sql
    with websockets.connect(url) as ws:
AttributeError: __enter__

no idea why its trying to use a function that doesn't exist?

After changing it back to async, I've started to get this error after a lot of successful pulls... but always within 5 seconds of starting the script.

      File "/home/path/main.py", line 573, in main
    await asyncio.gather(task1, task2)
  File "/home/path/main.py", line 463, in write_websocket_to_sql
    await ws.send(json.dumps(subscription_message))
  File "/home/anaconda3/envs/py39/lib/python3.9/site-packages/websockets/legacy/protocol.py", line 619, in send
    await self.ensure_open()
  File "/home/anaconda3/envs/py39/lib/python3.9/site-packages/websockets/legacy/protocol.py", line 920, in ensure_open
    raise self.connection_closed_exc()
websockets.exceptions.ConnectionClosedError: no close frame received or sent

so my questions are:

  1. How does the logic differ and what is happening when using async inside async?
  2. Do I need to just lengthen the timeout somehow or does this smell like a different problem?

Upvotes: 0

Views: 756

Answers (2)

hedgedandlevered
hedgedandlevered

Reputation: 2394

The websocket is closing the connection remotely. The error was occurring from using the Gemini websocket v1 instead of v2 for market data.

Upvotes: 0

kosciej16
kosciej16

Reputation: 7158

  1. It's not about extra async, it's about protocol that implements context managers in python.

In case of with keyword python calls __enter__ method when entering and __exit__.

with 1: # AttributeError: __enter__
    pass

int nor websockets.connect(url) class has implemented __enter__, so you get such error.

async_with assumes __aenter__ and __aexit__ are implemented, which is the case here.

  1. The error says that connections mean TCP connection was lost. There can be many reason, like problem with internet connection or problem with proxy that doesn't allow for long time connection, but it's rarely caused of too small timeout. You can enable debugging to get more insight to the problem.

Upvotes: 1

Related Questions