question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Usage of ContextVar in Fastapi

See original GitHub issue

First 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:open
  • Created 2 years ago
  • Reactions:5
  • Comments:7

github_iconTop GitHub Comments

6reactions
Sharleedahcommented, Mar 21, 2022

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

1reaction
Sharleedahcommented, Dec 3, 2022

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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

FastAPI save context that will be available in endpoints
FastAPI uses Starlette interface so you should be good to go. Regarding. But if endpoint doesnt have request: Request as parameter it gets ......
Read more >
contextvars — Context Variables — Python 3.11.1 ...
This module provides APIs to manage, store, and access context-local state. The ContextVar class is used to declare and work with Context Variables....
Read more >
SQL (Relational) Databases with Peewee - FastAPI
This class inherits from a special internal class used by Peewee. It has all the logic to make Peewee use contextvars instead of...
Read more >
Context object — Starlette Context 0.3.5 documentation
The context object utilizes ContextVar to store the information. This ContextVar is a native Python object, introduced in Python 3.7.
Read more >
ModuleNotFoundError: No module named '_contextvars
Fastapi contextvars. contextvars — Context Variables ¶ This module provides APIs to manage, store, and access context-local state. The ContextVar class is used ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found