Aller au contenu
EdgeServers
Blog

Gunicorn et Uvicorn en production — le tuning de workers que nous appliquons réellement

12 mai 2026 · 1 min de lecture · par Sudhanshu K.

Les services web Python en 2026 se divisent en deux camps : WSGI traditionnel (Django, Flask) servi via des workers sync Gunicorn, et ASGI moderne (FastAPI, Starlette, Django 5 async) servi via des workers Uvicorn sous un master Gunicorn. Les deux peuvent être de qualité prod. Aucun ne marche bien aux défauts.

La mauvaise config la plus courante que nous voyons : 2 × CPU + 1 workers tournant contre une app ASGI async qui devrait être un worker Uvicorn par cœur sans multiplicateur de concurrence. Le CPU reste inactif parce que chaque worker est mono-thread et que async tourne dans un seul event loop.

Le pattern Gunicorn + Uvicorn pour FastAPI

gunicorn app.main:app \
  --workers $(( $(nproc) )) \
  --worker-class uvicorn.workers.UvicornWorker \
  --bind 0.0.0.0:8000 \
  --timeout 30 \
  --graceful-timeout 30 \
  --keep-alive 5 \
  --max-requests 10000 \
  --max-requests-jitter 1000 \
  --access-logfile -

Un worker Uvicorn par cœur. Chaque worker fait tourner un event loop mono-thread. La concurrence async vient de l'attente d'I/O, pas du threading.

L'article complet couvre :

  • La formule sync-worker (2 × CPU) + 1 et où elle est fausse
  • Pourquoi --max-requests compte (memory creep lent, fragmentation GC)
  • --timeout vs --graceful-timeout — et l'ordre dans lequel ils s'enclenchent
  • Quand gthread (sync avec threads) est le bon choix
  • ProxyHeadersMiddleware pour la chaîne X-Forwarded-For
  • Lire gunicorn --print-config pour vérifier ce qui est réellement chargé

Nous livrons cette configuration sur chaque service Python managé.

Article complet disponible

Lire l'article complet