Search code examples
flaskpython-requestsgunicorn

python requests times out with flask app run on gunicorn


I am creating a flask app and running it on gunicorn, but when I use python's requests module it times out. Here is a minimal reproducible example:

from flask import Flask
import requests

API_URL = "http://127.0.0.1:8000"

def create_app():
    app = Flask(__name__)
    
    @app.route('/')
    def index():
        
        response = requests.get(API_URL + "/test")
        return response
    
    @app.route('/test')
    def test():
        return "test"
    
    return app

I run the code with gunicorn "app.main:create_app()". When I just change the index function to a simple return of text, it works no problem. However, when I run it with gunicorn, I get the error

[2024-04-06 11:04:54 -0400] [45422] [INFO] Starting gunicorn 20.0.4
[2024-04-06 11:04:54 -0400] [45422] [INFO] Listening at: http://127.0.0.1:8000 (45422)
[2024-04-06 11:04:54 -0400] [45422] [INFO] Using worker: sync
[2024-04-06 11:04:54 -0400] [45423] [INFO] Booting worker with pid: 45423
[2024-04-06 11:05:28 -0400] [45422] [CRITICAL] WORKER TIMEOUT (pid:45423)
[2024-04-06 11:05:28 -0400] [45423] [INFO] Worker exiting (pid: 45423)
[2024-04-06 11:05:28 -0400] [45436] [INFO] Booting worker with pid: 45436

After the timeout happens, the /test route gets called. Does anyone know why this is the case? Thank you!

Overall, I tried to call the local /test endpoint with python's requests. I was expecting it to instantly go through and return "test". It instead gave me the timeout error above.


Solution

  • The problem is not requests with gunicorn. If you change the URL to an external server, then it will probably work and not timeout.

    The problem here is that when you run gunicorn, by default it uses 1 worker only. So what's happening is that when you make a request to http://127.0.0.1:8000/ (index) the worker will handle that request and have no workers left to handle new requests until it finishes, but because inside index() you are making a request to your server, the worker will try to make a request to itself but there won't be workers available to handle that new request, creating a deadlock.

    To fix it try running gunicorn with more than 1 worker. gunicorn --workers 2 "app.main:create_app()"