Usage of ContextVar in Fastapi
See original GitHub issueFirst Check
- I added a very descriptive title to this issue.
- I used the GitHub search to find a similar issue and didn’t find it.
- I searched the FastAPI documentation, with the integrated search.
- I already searched in Google “How to X in FastAPI” and didn’t find any information.
- I already read and followed all the tutorial in the docs and didn’t find an answer.
- I already checked if it is not related to FastAPI but to Pydantic.
- I already checked if it is not related to FastAPI but to Swagger UI.
- I already checked if it is not related to FastAPI but to ReDoc.
Commit to Help
- I commit to help with one of those options 👆
Example Code
Structure:
- run.py
- app
- __init__.py
- database.py
- main.py
------------------Content __init__.py------------------
from contextvars import ContextVar
from fastapi import Request
class ContextWrapper:
def __init__(self, value):
self.__value: ContextVar = value
def set(self, value):
return self.__value.set(value)
def reset(self, token):
self.__value.reset(token)
return
def __module__(self):
return self.__value.get()
@property
def value(self):
return self.__value.get()
request: ContextWrapper = ContextWrapper(ContextVar("request", default=None))
db: str = ContextWrapper(ContextVar("db", default=None))
------------------Content database.py------------------
from sqlalchemy.orm import sessionmaker, declarative_base
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy import Column, String
engine = create_async_engine("sqlite+aiosqlite:///data.db", future=True, echo=False)
async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession)
Base = declarative_base()
class UserTable(Base):
__tablename__ = "User"
mail = Column(String, nullable=False, primary_key = True)
salt = Column(String, nullable=False)
hash = Column(String, nullable=False)
def __repr__(self): #how the object is shown when printed
return f"User('{self.mail}','{self.count}')"
------------------Content main.py------------------
from fastapi import Depends, FastAPI, Request
from app.database import engine, Base
app = FastAPI(
title="TEST APP",
description="",
version=1.0,
docs_url= None,
redoc_url= None
)
@app.middleware("http")
async def add_middleware(request: Request, call_next):
from app import db, request as ctx_request
from app.database import async_session
token = ctx_request.set(request)
async with async_session() as db_session:
async with db_session.begin():
db_token = db.set(db_session)
response = await call_next(request)
db.reset(db_token)
ctx_request.reset(token)
return response
@app.on_event("startup")
async def startup():
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
@app.get("/test", summary="TEST", include_in_schema=False)
async def test():
from app import db
from app.database import UserTable
user_obj = UserTable(mail="test@test.com",salt="test", hash="hash")
db.value.add(user_obj)
await db.value.flush()
return {"success": True}
------------------Content run.py------------------
from app.main import app
import uvicorn
if __name__ == '__main__':
uvicorn.run("run:app", host="0.0.0.0", port=80, reload = True, workers = 1)
Description
I am building an application with FastAPI for 200.000 users, where at some point at 10.000 are accessing the application at the same time. Fastapi will be of course be deployed with gunicorn/uvicorn with auto scaling and a loadbalancer in the aws. But there is one question, which i couldn’t solve. I do not get any errors but i cannot rule out that there can be a problem, when people use the application at the same time.
Question: Is the usage of ContextVar (see defintion in init.py and usage in main.py) secure, when many people access the api at the same time (thread etc. wise)? So that the database session or the request are set correctly in the http middleware, that i can access those contexts from any point in the application (when working on a request) without having to fear that may a function get a request context from another user (authentication etc. wise) Or do you have a better solution in mind?
Operating System
Linux, Windows, macOS, Other
Operating System Details
No response
FastAPI Version
0.75.0
Python Version
3.10.0
Additional Context
No response
Issue Analytics
- State:
- Created 2 years ago
- Reactions:5
- Comments:7
Top GitHub Comments
Mhm i mean your solution is better than the default, where you handover each object individually, but you still have to hand over the request for every function… This is what i want to avoid with the ContextVar, where i can access the objects for each request through simple objects without any handover
Hey @Elfpkck i went with the ContextVar Solution, due to a more lean code in general (i can access the db session, request, session … without having to put the request arg in every function). After tons of tests, mostly stressing the parallelism, there was not a single issue.