py-opslisted
Install: claude install-skill AllThingsSmitty/agent-skills
# Production Python Operations
Python web apps have two distinct runtime models — synchronous (WSGI) and asynchronous (ASGI) — with different servers, worker models, and operational characteristics. Mixing them up or misconfiguring workers is the most common source of Python production problems.
## WSGI vs ASGI
| | WSGI | ASGI |
| ----------------- | ---------------------- | ------------------------------------------- |
| Frameworks | Django, Flask, Falcon | FastAPI, Starlette, Django 4+ (async views) |
| Server | gunicorn | uvicorn, hypercorn, daphne |
| Concurrency model | One request per worker | Many requests per worker (async) |
| I/O concurrency | Via multiple workers | Via event loop within each worker |
**WSGI** handles one request per worker at a time. Scale by adding workers. Blocking I/O is fine — each worker blocks independently.
**ASGI** handles many requests per worker concurrently via the event loop. Blocking I/O kills concurrency (see `py-async`). Fewer workers needed, but each worker must be async-safe.
## Gunicorn worker sizing (WSGI)
The classic formula: `(2 × CPU cores) + 1`.
```bash
gunicorn myapp.wsgi:application \
--workers 5 \ # 2 × 2 cores + 1
--worker-class sync \ # default; gthread for threaded
--timeout 30 \
--bind 0.0.0.0:8000
```
For WSGI apps with heavy I/O (database call