Long Polling in Python with Flask
Asked Answered
H

1

10

I'm trying to do long polling with JQuery and Python under the Flask Framework.

Having done long polling before in PHP, I've tried to go about it in the same way:

A script/function that has a while(true) loop, checking for changes periodically eg.every 0,5 seconds in the database, and returns some data when a change occurs.

So in my ini.py I've created an app.route to /poll for JQuery to call. JQuery gives it some information about the client's current state, and the poll() function compares this with what's currently in the database. The loop is ended and returns information when a change is observed.

Here's the python code:

@app.route('/poll')
def poll():
client_state = request.args.get("state")

    #remove html encoding + whitesapce from client state
    html_parser = HTMLParser.HTMLParser()
    client_state = html_parser.unescape(client_state)
    client_state = "".join(client_state.split())

    #poll the database
    while True:
        time.sleep(0.5)
        data = get_data()
        json_state = to_json(data)
        json_state = "".join(data) #remove whitespace

        if json_state != client_state:
            return "CHANGE"

The problem is that, when the code above starts polling, the server appears to be overloaded and other Ajax calls, and other requests like loading a "loading" image to the html using JQuery are unresponsive and timeout.

For completion's sake I've included the JQuery here:

function poll() {

queryString = "state="+JSON.stringify(currentState);

$.ajax({
    url:"/poll",
    data: queryString,
    timeout: 60000,
    success: function(data) {
        console.log(data);
        if(currentState == null) {
            currentState = JSON.parse(data);
        }
        else {
            console.log("A change has occurred");
        }

        poll();

    },
    error: function(jqXHR, textStatus, errorThrown) {

        console.log(jqXHR.status + "," + textStatus + ", " + errorThrown);

        poll();

    }
});

}

Does this need to multi-threaded or something? Or does anyone have any idea why I'm experiencing this behavior?

Thanks in advance!! :)

Hymeneal answered 8/4, 2015 at 14:15 Comment(1)
See #14814701Pear
W
9

Just as the link @Robᵩ mentioned, you flask app is just overload. That's because a flask app is in single threading mode by default when running with app.run(), so it can only serve one request per time.

You can start multi threading with:

if __name__ == '__main__':
    app.run(threaded=True)

Or using a WSGI server like gunicorn or uwsgi to serve flask with multi processing:

gunicorn -w 4 myapp:app

Hopes you're enjoying with Python and Flask!

Washbowl answered 26/8, 2015 at 3:52 Comment(3)
In general though WSGI applications are not suitable for long polling at any sort of scale, although the same applies to PHP as well. This is because both Python when using WSGI and PHP are synchronous systems and need a process or thread to handle every request. Thus to handle a large number of concurrent long poll requests, you need a lot of capacity (processes or threads). Long polling is better off implemented using an async web server and framework.Loverly
The alternative if using gunicorn is to use coroutines via the eventlet or gevent workers. Doing that though does place a lot of restrictions on your application as you can only use clients for backend services and databases which are coroutine aware to avoid them blocking the whole process. So coroutines are not simply magic that makes everything good.Loverly
@GrahamDumpleton Yes, an async server would like Tornado be much better, and usually that's my first choice for API building or WebSocket server.Washbowl

© 2022 - 2024 — McMap. All rights reserved.