How to get Flask/Gunicorn to handle concurrent requests for the same Route?

倖福魔咒の 提交于 2021-01-26 22:27:05

问题


tl;dr A method decorated with route can't handle concurrent requests while Flask is served behind a gunicorn started with multiple workers and threads, while two different methods handle concurrent requests fine. Why is this the case, and how can the same route be served concurrently?


I have this simple flask app:

from flask import Flask, jsonify
import time
app = Flask(__name__)

@app.route('/foo')
def foo():
    time.sleep(5)
    return jsonify({'success': True}), 200

@app.route('/bar')
def bar():
    time.sleep(5)
    return jsonify({'success': False}), 200

If I run this via:

gunicorn test:app -w 1 --threads 1

If I quickly open up /bar and /foo in two different tabs in a browser, whichever tab I hit enter on first will load in 5 seconds, and the second tab will load in 10 seconds. This makes sense because gunicorn is running one worker with one thread.

If I run this via either:

gunicorn test:app -w 1 --threads 2
gunicorn test:app -w 2 --threads 1

In this case, opening up /foo and /bar in two different tabs both take 5 seconds. This makes sense, because gunicorn is running either 1 worker with two threads, or two workers with one thread each, and can serve up the two routes at the same time.

However, If I open up two /foo at the same time, regardless of the gunicorn configuration, the second tab will always take 10 seconds.

How can I get the same method decorated by route to serve concurrent requests?


回答1:


This problem is probably not caused by Gunicorn or Flask but by the browser. I just tried to reproduce it. With two Firefox tabs it works; but if I run two curl processes in different consoles then they get served as expected (in parallel), and their requests are handled by different workers - this can be checked by enabling --log-level DEBUG while starting gunicorn.

I think this is because Firefox (and maybe other browsers) open a single connection to the server for each URL; and when you open one page on two tabs, their requests are sent through the same (kept-alive) connection and as a result come to the same worker.

As a result, even using async worker like eventlet will not help: async worker may handle multiple connections at a time, but when two requests land on the same connection then they will necessarily be handled one-by-one.



来源:https://stackoverflow.com/questions/35051499/how-to-get-flask-gunicorn-to-handle-concurrent-requests-for-the-same-route

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!