Dmitry Zuev
Dmitry Zuev

Reputation: 142

Flask request.form.get too slow?

I am using Flask for my Web Api service.

Finding that my services sometimes (1/100 requests) respond really slow (seconds), I started debugging, which showed me that sometimes the service hangs on reading the request field.

@app.route('/scan', methods=['POST'])
def scan():
    start_time = time.time()
    request_description = request.form.get('requestDescription')
    end_time = time.time()
    app.logger.debug('delay is ' + end_time-start_time)

Here I found that delay between start_time and end_time can be up to 2 minutes.

I've read about using Flask's Werkzeug as a production server, so I tried GUnicorn as an alternative - same thing.

I feel that my problem is somehow similar to this one, with the difference that another server didn't solve the problem.

I tried to profile the app using cProfile and SnakeViz, but with the non-prod Werkzeug server - as I don't get how to profile python apps running on GUnicorn. (maybe anyone here knows how to?)

My POST requests contain description and a file. The file can vary in size, but the logs show that the issue reproduces regardless of the file size.

People also usually say that Flask should be used in Nginx-[normal server]-flask combo, but as I use the service inside Openshift, I doubt this has any meaning. (HaProxy works as a balancer)

So my settings: Alpine 3.8.1 GUnicorn: workers:3 threads:1

What happens under the hood when I call this?

request.form.get('requestDescription')

How can I profile Python code under GUnicorn? Did anyone else encounter such a problem?

Any help will be appreciated

Upvotes: 5

Views: 660

Answers (1)

Kyle Nathan
Kyle Nathan

Reputation: 35

I did face this issue as well. I was uploading a video file using request.post(). Turns out that the video uploading was not the issue.

The timing bottleneck was the request.form.get(). While I am still trying to figure out the issue, you can use Flask Monitoring Dashboard to time profile the code

Turns out that the under the hood is return self._sock.recv_into(b) if you use the profiler

Upvotes: 0

Related Questions