supertokens/supertokens-python

supertokens FastAPI middleware uses BaseHTTPMiddleware which breaks async/background tasks

atambo opened this issue · 7 comments

atambo commented

See the starlette issue as well as the limitations section of the documentation.

It seems like using BaseHTTPMiddleware breaks some things with async/background tasks in FastAPI and people generally recommend switching your middleware to be pure ASGI middleware for maximum compatibility.

Unfortunately, I've been noticing this issue ever since I integrated the supertokens middleware into my application.

Thanks for opening this issue @atambo . We will have a look at this in the coming week.

atambo commented

Seems like starlette was thinking about deprecating BaseHTTPMiddleware but ended up backing off from doing so:
encode/starlette#1898

However, it still seems like the recommended approach is to use a pure ASGI middleware.

Hi @atambo, Thanks for pointing this out. I quickly tried to replace BaseHTTPMiddleware. But it was getting slightly complicated. Starlette is on a lower level and the objects don't seem easily convertable into each other (esp. Message <-> Response). So we will take a look at this when at a later point in time.

Keeping this issue open since it's valid. We will try to get resolve this as soon as we have time. In the meantime, I can help you with finding a workaround for your use case if you provide more details :)

Hi, this is causing issues for me currently, I'd like to run an async function in a BackgroundTask but having the SuperTokens middleware is blocking my main event loop. I need something like the following:

import asyncio
from fastapi import BackgroundTasks, FastAPI
from fastapi import FastAPI
from supertokens_python import init, InputAppInfo, SupertokensConfig
from supertokens_python.framework.fastapi import get_middleware
from supertokens_python.recipe import dashboard, emailpassword, session, userroles


app = FastAPI()

app.add_middleware(get_middleware())

init(
    app_info=InputAppInfo(
        app_name="name",
        api_domain="localhost",
        website_domain="localhost",
        api_base_path="/auth",
        website_base_path="/auth",
    ),
    supertokens_config=SupertokensConfig(
        connection_uri= "uri",
        api_key= "key",
    ),
    framework="fastapi",
    recipe_list=[
        session.init(),
        userroles.init(),
        dashboard.init(),
        emailpassword.init(),
    ],
    mode="asgi",
)

@app.get("/")
async def root():
    return {"message": "Hello World"}

async def simple_task():
    await asyncio.sleep(10)
    print("completed")

@app.post("/test")
async def test(background_tasks: BackgroundTasks):
    background_tasks.add_task(simple_task)
    return {"message": "Task started"}

@AngusParsonson I tried your code, it seems to be working for me and is able to run the async tasks. What's the error that your're seeing on your machine?

Hi @KShivendu, thanks for the response.

There is no error, it is just that the main event loop is blocked whilst the task is running. If you try to hit a simple get endpoint whilst the background task is running, then it will not complete until the background task is finished.

This is an issue with starlette, the way I got around it was by using asyncio.create_task() instead of the background task.

Ahh yes. I'll try to dive into this and find a clean solution sometime soon.

Good to know that you already found a workaround in the meantime. I believe it's sufficient to solve your problem for now?