Search code examples
pythonwebsocketrx-pyflask-sockets

Handling websocket disconnect in Python Flask server using RxPY for push based events


Context

I am using RxPY to enable sending push based events via websockets. I am using flask-sockets in a Flask server with gevent. The events class contains an rx.subject.BehaviorSubject that acts as an event publisher, while the websocket clients subscribe to changes.

Problem

I want to be able to detect when a client is disconnected so I could properly dispose the resources. The problem is when the socket is disconnected and ws.send throws an exception but it's inside the lambda.

Solution?

Is there a way to pass the exception to the parent function instead?

An alternative solution would be to detect the websocket disconnect without calling ws.send and that could be checked outside the lambda, though I could not find such method in the flask-sockets library.

@sockets.route('/ws/events')
def wsEvents(ws):
    sub = None
    disp = None
    try:
        print("socket opened")
        def update_fn(x):
            print(x) 
            ws.send(json.dumps(x))

        sub = events.get_sub(None)

        if sub is not None:
            disp = sub.subscribe(lambda x: update_fn(x))
        else:
            raise Exception('Undefined sub') 

        while not ws.closed:
            gevent.sleep(1)
            pass

    except Exception as e:
        print(e) 

    finally:
        print("socket closed")
        if disp is not None:
            disp.dispose()

Solution

  • I have found a workaround, detecting the socket disconnect event using a gevent timeout method like this:

    while not ws.closed:
        gevent.sleep(0.1)
        try:
            data = gevent.with_timeout(0.1, ws.receive, timeout_value="")
            if data is None:
                raise Exception("socket closed")
        except:
            break
    

    Now it's possible to dispose the resources as the method returns None on socket disconnected event.