-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Description
Question
Context
I’m running a FastAPI application on Azure Web App (Linux, containerized) using Gunicorn + Uvicorn workers.
The app is an MCP (Model Context Protocol) server that connects to Rally via pyral.
Because Rally connections are cached per worker, all requests from the same client need to be routed to the same worker.
If a request lands on a different worker, the Rally API responds with a BAD session ID error because the cached connection is no longer valid.
What I Tried
1. Gunicorn Startup Command
gunicorn -k uvicorn.workers.UvicornWorker \
-w 2 \
-b 0.0.0.0:8000 \
main:app \
--keep-alive 120 \
--timeout 240 \
--worker-connections 1000 \
--max-requests 1000 \
--max-requests-jitter 50 \
--preload \
--log-level info
2. Custom Session Middleware (FastAPI)
Validates that a request always maps back to the same worker.
3. Debugging
Logged worker PID + session ID on each request.
Observed the same client’s requests hitting different workers intermittently.
Example log:
Worker 1234 → Session=sess_abc_1234
Worker 5678 → Session=sess_def_5678 # Same client, different worker
Problem
Client requests are not consistently routed to the same Gunicorn worker.
Cached Rally sessions exist only in the worker process that created them.
When a client hits another worker, Rally rejects the request with BAD session ID.
Expected Behavior
All requests from a given client should always land on the same worker.
Session affinity should be preserved consistently until session expiry.
### Questions for the Community
-
Is it possible to achieve worker-level sticky sessions with FastAPI + Gunicorn on Azure Web App?
-
Should I run a single worker per instance (e.g., --workers 1) to avoid this problem (I Actually tried and found out the Server crashes a lot )?
-
Should I share Rally session state across workers (e.g., Redis or DB-backed session store) instead of relying on per-worker caching(Tried it but due to mounting with FASTAPI, the session management didn't got intercepted for the main MCP server URL)?
Note:
Have to use statefull http as using sampling/elicitation in my server
mcp = FastMCP("Rally MCP Server",stateless_http=True)
Additional Context
Environment
Azure Web App (Linux, Code Deploy)
FastAPI + Gunicorn + Uvicorn workers
Python 3.13
pyral (Rally API client)