Uwsgi: how to gracefully exit from application when use uwsgi websocket?

Created on 6 Nov 2014  路  6Comments  路  Source: unbit/uwsgi

hi,

when use websocket in uwsgi, if client close websocket connection, I will get en exception like " "unable to receive websocket message", so
i catch it as below:
try:
message = uwsgi.websocket_recv()
except IOError:
### how to do?
a compliant method to return [' '], but uwsgi will raise a exception "headers already sent",
so what should i do?

thanks

Most helpful comment

uwsgi.websocket_handshake() internally does the same thing of start_response() (effectively the websocket handshake is a header exchange). If you cannot stop your app for calling it again you can wrap the flask callable (as an example) to map start_response as a noop for a specific url:

def application(environ, start_response):
    if environ['PATH_INFO'] == '/websocket':
        return app(environ, fake_start_response):
    return app(app, start_response)

All 6 comments

If your client brutally close the connection it is the right thing to do to generate an IOError (it is what happens at lower level). Are you sure you are not calling start_response() again ?

Maybe I find the problem.
If i write the code as below, uwsgi will have a error log like "headers already sent"

def application(env, start_response):
uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', ''))
while True:
    try:
        msg = uwsgi.websocket_recv()
    except IOError:

        status = '200 OK'
        response_headers = [('Content-type', 'text/plain')]
        start_response(status, response_headers)

        return ['']

    uwsgi.websocket_send(msg)

and if I do not call start_response, everything is good. so the question is, uwsgi websocket api do the same thing like start_response function, when the req->headers_sent flag become true before I
call the start_response function?

and, if I use flask or webapp2 together with uwsgi , I write logic and return response in handler, but in framework, start_response will be called forcibly, so in this condition, how to catch client close websocket connection and gracefully exit the handler of framework without any error like "headers already sent" ?

thanks

uwsgi.websocket_handshake() internally does the same thing of start_response() (effectively the websocket handshake is a header exchange). If you cannot stop your app for calling it again you can wrap the flask callable (as an example) to map start_response as a noop for a specific url:

def application(environ, start_response):
    if environ['PATH_INFO'] == '/websocket':
        return app(environ, fake_start_response):
    return app(app, start_response)

the idea of fake_start_response is wonderful, thanks very much

See the code example here:
http://uwsgi-docs.readthedocs.io/en/latest/articles/OffloadingWebsocketsAndSSE.html#common-pitfalls

However, I think a better approach is to check whether the request is a WebSocket handshake:

def application(environ, start_response):
    if (environ.get('HTTP_CONNECTION', '').lower() == 'upgrade' and
            environ.get('HTTP_UPGRADE', '').lower() == 'websocket'):
        # The connection is upgrading to websocket. Use fake_start_response for it
        start_response = fake_start_response
    return sio_application(environ, start_response)


def fake_start_response(status, headers, exc_info=None):
    pass

Sorry to intrude but what if someone is using uwsgi in django?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

yoichi picture yoichi  路  7Comments

vlcinsky picture vlcinsky  路  3Comments

adamhadani picture adamhadani  路  4Comments

cancan101 picture cancan101  路  4Comments

haytham-salhi picture haytham-salhi  路  3Comments