sanic-org / sanic

Accelerate your web app development | Build fast. Run fast.

Home Page:https://sanic.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

New websockets, handling disconnects

heshiming opened this issue · comments

Is there an existing issue for this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe.

I'm using version 23.6.0, so it's new websockets. I have followed the guide to build something like this:

async def handler(request, ws):
    while True:
        data = "hello!"
        try:
            await ws.send(data)
            data = await ws.recv()
        except Exception as e:
            print(e)
            break
    clean_up()

bp.add_websocket_route(handler, '/ws')

I discovered that when the client disconnects, no exceptions are thrown in this above code. Making it difficult for me to clean up things. What's worse is that the execution of this handler somehow stops in a disconnect, no subsequent code gets run.

I read the source code and figured out the following mechanism to tackle a disconnect:

def ws_disconnect(my_mess, fut):
    clean_up(my_mess)

async def handler(request, ws):
    ws.connection_lost_waiter.add_done_callback(functools.partial(ws_disconnect, "my_mess"))
    ...

It works, as the WebsocketImplProtocol calls it upon disconnect. But I could help but thinking there should be a better mechanism to handle websocket clean ups. What am I supposed to do to handle disconnects?

Describe the solution you'd like

Keep the handler running upon disconnect, and give it a chance to handle exception or check for "connected" attribute.

Additional context

No response

I'd suggest this:

from asyncio import shield

async def cleanup():
    for i in range(10):
        print("Cleaning up")
        await sleep(1)


@app.websocket("/")
async def handler(request: Request, ws):
    try:
        while True:
            ...
    finally:
        print("Connection closed")
        await shield(cleanup())

You might not need the shield, but it may be helpful

Thank you Adam! finally works!