{"id":17929421,"url":"https://github.com/iximiuz/flask-gevent-tutorial","last_synced_at":"2025-07-15T17:44:12.554Z","repository":{"id":50146975,"uuid":"230527221","full_name":"iximiuz/flask-gevent-tutorial","owner":"iximiuz","description":"How to use Flask with gevent (uWSGI and Gunicorn editions)","archived":false,"fork":false,"pushed_at":"2019-12-29T10:57:50.000Z","size":16,"stargazers_count":94,"open_issues_count":0,"forks_count":28,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-14T21:46:38.021Z","etag":null,"topics":["asynchronous","asyncio","flask","gevent","gunicorn","nginx","python","uwsgi"],"latest_commit_sha":null,"homepage":"https://iximiuz.com/en/posts/flask-gevent-tutorial/?utm_medium=github\u0026utm_source=repo","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/iximiuz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-12-27T22:31:45.000Z","updated_at":"2025-02-26T02:15:42.000Z","dependencies_parsed_at":"2022-09-24T21:21:13.368Z","dependency_job_id":null,"html_url":"https://github.com/iximiuz/flask-gevent-tutorial","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iximiuz%2Fflask-gevent-tutorial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iximiuz%2Fflask-gevent-tutorial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iximiuz%2Fflask-gevent-tutorial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iximiuz%2Fflask-gevent-tutorial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/iximiuz","download_url":"https://codeload.github.com/iximiuz/flask-gevent-tutorial/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245210913,"owners_count":20578315,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asynchronous","asyncio","flask","gevent","gunicorn","nginx","python","uwsgi"],"created_at":"2024-10-28T21:09:11.114Z","updated_at":"2025-03-24T04:31:01.462Z","avatar_url":"https://github.com/iximiuz.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# How to use Flask with gevent (uWSGI and Gunicorn editions)\n\n## Create simple Flask application\n\nFirst, we need to emulate a slow 3rd party API:\n\n```python\n# slow_api/api.py\nimport os\n\nimport asyncio\nfrom aiohttp import web\n\nasync def handle(request):\n    delay = float(request.query.get('delay') or 1)\n    await asyncio.sleep(delay)\n    return web.Response(text='slow api response')\n\napp = web.Application()\napp.add_routes([web.get('/', handle)])\n\nif __name__ == '__main__':\n    web.run_app(app, port=os.environ['PORT'])\n```\n\nThen, we create a simple flask application with a dependency on the slow 3rd party API:\n\n```python\n# flask_app/app.py\nimport os\n\nimport requests\nfrom flask import Flask, request\n\napi_port = os.environ['PORT_API']\napi_url = f'http://slow_api:{api_port}/'\n\napp = Flask(__name__)\n\n@app.route('/')\ndef index():\n    delay = float(request.args.get('delay') or 1)\n    resp = requests.get(f'{api_url}?delay={delay}')\n    return 'Hi there! ' + resp.text\n```\n\n## Deploy Flask application using Flask dev server\n\n```bash\n# Build and start app served by Flask dev server\n$ docker-compose -f sync-devserver.yml build\n$ docker-compose -f sync-devserver.yml up\n\n# Test single-threaded deployment\n$ ab -r -n 10 -c 5 http://127.0.0.1:3000/?delay=1\n\u003e Concurrency Level:      5\n\u003e Time taken for tests:   10.139 seconds\n\u003e Complete requests:      10\n\u003e Failed requests:        0\n\u003e Requests per second:    0.99 [#/sec] (mean)\n\n# Test multi-threaded deployment\n$ ab -r -n 10 -c 5 http://127.0.0.1:3001/?delay=1\n\u003e Concurrency Level:      5\n\u003e Time taken for tests:   3.069 seconds\n\u003e Complete requests:      10\n\u003e Failed requests:        0\n\u003e Requests per second:    3.26 [#/sec] (mean)\n```\n\n## Deploy Flask application using uWSGI (4 worker processes x 50 threads each)\n\n```bash\n# Build and start app served by uWSGI\n$ docker-compose -f sync-uwsgi.yml build\n$ docker-compose -f sync-uwsgi.yml up\n\n$ ab -r -n 2000 -c 200 http://127.0.0.1:3000/?delay=1\n\u003e Concurrency Level:      200\n\u003e Time taken for tests:   12.685 seconds\n\u003e Complete requests:      2000\n\u003e Failed requests:        0\n\u003e Requests per second:    157.67 [#/sec] (mean)\n```\n\n## Deploy Flask application using Gunicorn (4 worker processes x 50 threads each)\n\n```bash\n# Build and start app served by Gunicorn\n$ docker-compose -f sync-gunicorn.yml build\n$ docker-compose -f sync-gunicorn.yml up\n\n$ ab -r -n 2000 -c 200 http://127.0.0.1:3000/?delay=1\n\u003e Concurrency Level:      200\n\u003e Time taken for tests:   13.427 seconds\n\u003e Complete requests:      2000\n\u003e Failed requests:        0\n\u003e Requests per second:    148.95 [#/sec] (mean)\n```\n\n## Deploy Flask application using gevent.pywsgi\n\nFirst, we need to create an entrypoint:\n\n```python\n# flask_app/pywsgi.py\nfrom gevent import monkey\nmonkey.patch_all()\n\nimport os\nfrom gevent.pywsgi import WSGIServer\nfrom app import app\n\nhttp_server = WSGIServer(('0.0.0.0', int(os.environ['PORT_APP'])), app)\nhttp_server.serve_forever()\n```\n\nNotice, how it patches our flask application. Without `monkey.patch_all()` there would be no benefit from using gevent here.\n\n```bash\n# Build and start app served by gevent.pywsgi\n$ docker-compose -f async-gevent-pywsgi.yml build\n$ docker-compose -f async-gevent-pywsgi.yml up\n\n$ ab -r -n 2000 -c 200 http://127.0.0.1:3000/?delay=1\n\u003e Concurrency Level:      200\n\u003e Time taken for tests:   17.536 seconds\n\u003e Complete requests:      2000\n\u003e Failed requests:        0\n\u003e Requests per second:    114.05 [#/sec] (mean)\n```\n\n## Deploy Flask application using uWSGI + gevent\n\nFirst, we need to create an entrypoint:\n\n```python\n# flask_app/patched.py\nfrom gevent import monkey\nmonkey.patch_all()\n\nfrom app import app  # re-export\n```\n\nWe need to patch very early.\n\n```bash\n# Build and start app served by uWSGI + gevent\n$ docker-compose -f async-gevent-uwsgi.yml build\n$ docker-compose -f async-gevent-uwsgi.yml up\n\n$ ab -r -n 2000 -c 200 http://127.0.0.1:3000/?delay=1\n\u003e Time taken for tests:   13.164 seconds\n\u003e Complete requests:      2000\n\u003e Failed requests:        0\n\u003e Requests per second:    151.93 [#/sec] (mean)\n```\n\n## Deploy Flask application using Gunicorn + gevent\n\nThis setup uses the same `patched.py` entrypoint.\n\n```bash\n# Build and start app served by Gunicorn + gevent\n$ docker-compose -f async-gevent-gunicorn.yml build\n$ docker-compose -f async-gevent-gunicorn.yml up\n\n$ ab -r -n 2000 -c 200 http://127.0.0.1:3000/?delay=1\n\u003e Concurrency Level:      200\n\u003e Time taken for tests:   17.839 seconds\n\u003e Complete requests:      2000\n\u003e Failed requests:        0\n\u003e Requests per second:    112.11 [#/sec] (mean)\n```\n\n## Use Nginx reverse proxy in front of application server\n\nSee `nginx-gunicorn.yml` and `nginx-uwsgi.yml`:\n\n```bash\n$ docker-compose -f nginx-gunicorn.yml build\n$ docker-compose -f nginx-gunicorn.yml up\n\n# or\n\n$ docker-compose -f nginx-uwsgi.yml build\n$ docker-compose -f nginx-uwsgi.yml up\n\n# and then:\n\n$ ab -r -n 2000 -c 200 http://127.0.0.1:8080/?delay=1\n\u003e ...\n```\n\n## Bonus: make psycopg2 gevent-friendly with psycogreen\n\ngevent patches only modules from the Python standard library. If we use\n3rd party modules, like psycopg2, corresponding IO will still be blocking:\n\n```python\n# psycopg2/app.py\n\nfrom gevent import monkey\nmonkey.patch_all()\n\nimport os\n\nimport psycopg2\nimport requests\nfrom flask import Flask, request\n\napi_port = os.environ['PORT_API']\napi_url = f'http://slow_api:{api_port}/'\n\napp = Flask(__name__)\n\n@app.route('/')\ndef index():\n    conn = psycopg2.connect(user=\"example\", password=\"example\", host=\"postgres\")\n    delay = float(request.args.get('delay') or 1)\n    resp = requests.get(f'{api_url}?delay={delay/2}')\n\n    cur = conn.cursor()\n    cur.execute(\"SELECT NOW(), pg_sleep(%s)\", (delay/2,))\n    \n    return 'Hi there! {} {}'.format(resp.text, cur.fetchall()[0])\n```\n\nWe expect ~2 seconds to perform 10 one-second-long HTTP requests with concurrency 5,\nbut the test shows \u003e5 seconds due to the blocking behavior of psycopg2 calls:\n\n```bash\n$ docker-compose -f bonus-psycopg2-gevent.yml build\n$ docker-compose -f bonus-psycopg2-gevent.yml up\n\n$ ab -r -n 10 -c 5 http://127.0.0.1:3000/?delay=1\n\u003e Concurrency Level:      5\n\u003e Time taken for tests:   6.670 seconds\n\u003e Complete requests:      10\n\u003e Failed requests:        0\n\u003e Requests per second:    1.50 [#/sec] (mean)\n```\n\nTo bypass this limitation, we need to use psycogreen module to patch psycopg2:\n\n\n```python\n# psycopg2/patched.py\n\nfrom psycogreen.gevent import patch_psycopg\npatch_psycopg()\n\nfrom app import app\n```\n\n```bash\n$ docker-compose -f bonus-psycopg2-gevent.yml build\n$ docker-compose -f bonus-psycopg2-gevent.yml up\n\n$ ab -r -n 10 -c 5 http://127.0.0.1:3001/?delay=1\n\u003e Concurrency Level:      5\n\u003e Time taken for tests:   3.148 seconds\n\u003e Complete requests:      10\n\u003e Failed requests:        0\n\u003e Requests per second:    3.18 [#/sec] (mean)\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiximiuz%2Fflask-gevent-tutorial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fiximiuz%2Fflask-gevent-tutorial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiximiuz%2Fflask-gevent-tutorial/lists"}