ADR-0024: Adopt uvicorn[standard] for Enhanced Server PerformanceΒΆ
- Status: Accepted
- Date: 2025-12-21
- Deciders: Core Engineering Team
ContextΒΆ
ContextForge uses Gunicorn with Uvicorn workers (uvicorn.workers.UvicornWorker) as its production ASGI server stack. The base uvicorn package provides functional async HTTP serving, but lacks optional performance-enhancing components that can provide 15-30% throughput improvements with zero code changes.
The uvicorn package offers a [standard] extras bundle that includes:
- uvloop: A Cython/libuv-based event loop (2-4x faster than asyncio on Linux/macOS)
- httptools: A C extension for HTTP parsing (based on Node.js http-parser)
- websockets: WebSocket protocol implementation
- watchfiles: Efficient file watching for development
--reload
Without these extras, Uvicorn falls back to:
- Python's standard
asyncioevent loop - Python's pure-Python HTTP parser
- Basic file watching mechanisms
DecisionΒΆ
We will adopt uvicorn[standard] as the default uvicorn installation to enable high-performance server components automatically.
Change:
Components included:
| Package | Purpose | Platform Support |
|---|---|---|
uvloop | Fast event loop (libuv-based) | Linux, macOS only |
httptools | Fast HTTP parsing (C extension) | All platforms |
websockets | WebSocket support | All platforms |
watchfiles | Fast file watching for βreload | All platforms |
How it works:
- When Gunicorn spawns
UvicornWorkerprocesses, Uvicorn automatically detects and uses these high-performance components - No configuration changes required - detection is automatic
- On Windows,
uvloopgracefully skips (unavailable), buthttptoolsstill provides benefits
ConsequencesΒΆ
PositiveΒΆ
- 15-30% higher throughput - Faster event loop and HTTP parsing reduce per-request overhead
- Lower latency - uvloop provides 20-40% lower event loop latency
- Zero code changes - Drop-in enhancement, automatically detected by Uvicorn
- Consistency - Matches other projects in the repository (mcp_eval_server)
- Better development experience - watchfiles provides faster, more reliable
--reload - Production-ready - Used by major deployments (Microsoft, Mozilla, Sentry)
NegativeΒΆ
- Platform-specific behavior - uvloop unavailable on Windows (graceful fallback)
- Binary dependencies - Requires compilation or prebuilt wheels (available for all major platforms)
- Slightly larger install - Additional packages (~5MB)
NeutralΒΆ
- No configuration needed - Uvicorn auto-detects available components
- Transparent to application - FastAPI/Starlette code unchanged
Performance ImpactΒΆ
Based on uvloop and httptools benchmarks:
| Metric | Base Uvicorn | With [standard] | Improvement |
|---|---|---|---|
| Event loop latency | Baseline | -20-40% | uvloop |
| HTTP parsing overhead | Baseline | -40-60% | httptools |
| Requests/second | Baseline | +15-30% | Combined |
--reload responsiveness | Baseline | Faster | watchfiles |
Real-world impact:
- Simple JSON endpoints: 15-25% faster
- WebSocket connections: Better handling via optimized websockets library
- Development cycle: Faster file change detection with watchfiles
- Memory: Similar (slight increase for additional packages)
Alternatives ConsideredΒΆ
| Option | Why Not |
|---|---|
| Base uvicorn only | Leaves 15-30% performance on the table |
| Manual installation of extras | Error-prone, inconsistent across environments |
| Granian (Rust HTTP server) | Larger migration, under evaluation (see #1695) |
| Hypercorn | Less community adoption, similar feature set |
Relationship to Granian MigrationΒΆ
This change is complementary to the potential Granian migration (#1695):
- uvicorn[standard]: Low-effort optimization (this ADR) - implement now
- Granian: Larger migration to Rust-based server - evaluate separately
If Granian is adopted in the future, this change would be superseded. Until then, uvicorn[standard] provides immediate benefits with minimal risk.
Migration PathΒΆ
- Update
pyproject.toml:uvicorn[standard]>=0.38.0 - Reinstall dependencies:
uv syncorpip install -e . - Verify extras installed:
pip list | grep -E "uvloop|httptools" - Run test suite:
make test - Benchmark (optional): Compare RPS before/after
VerificationΒΆ
# Check installed packages
uv pip list | grep -E "uvicorn|uvloop|httptools|websockets|watchfiles"
# Expected output (Linux/macOS):
# httptools 0.6.x
# uvicorn 0.38.0
# uvloop 0.21.x
# watchfiles 1.x.x
# websockets 15.x.x
# On Windows, uvloop will be absent (expected)
StatusΒΆ
This decision has been implemented. The pyproject.toml now specifies uvicorn[standard]>=0.38.0.
ReferencesΒΆ
- GitHub Issue: #1699
- Related Issue: #1695 (Granian evaluation)
- uvicorn deployment docs: https://www.uvicorn.org/deployment/
- uvloop GitHub: MagicStack/uvloop
- httptools GitHub: MagicStack/httptools
- Gunicorn + Uvicorn integration: https://www.uvicorn.org/#running-with-gunicorn