supertokens / supertokens-python

Python SDK for SuperTokens
https://supertokens.com
Other
127 stars 35 forks source link

syncio functions do not work in FastAPI #501

Closed virajkanwade closed 4 months ago

virajkanwade commented 4 months ago

https://github.com/supertokens/supertokens-python/blob/master/supertokens_python/async_to_sync_wrapper.py

I want to call create_or_update_tenant after init but before the app starts.

The standard way to run a FastAPI application is

uvicorn main:app

or

uvicorn --factory main:create_app

syncio functions try to run loop.run_until_complete(co) which results in loop already running error.

There is provision to enable nest_asyncio, but it only works with asyncio loops.

uvicorn by default uses uvloop which is not compatible with nest_asyncio.

One workaround is to tell uvicorn to use asyncio

uvicorn main:app --loop asyncio

This takes almost 25% performance hit.

Two potential solutions:

  1. Implement actual sync versions of the functions (might not really be feasible)
  2. Update the current implementation of sync wrapper; If uvloop and running, use the hack below.
    import asyncio
    import nest_asyncio

    _cur_event_loop_policy = asyncio.get_event_loop_policy()
    asyncio.set_event_loop_policy(asyncio.DefaultEventLoopPolicy())
    loop = asyncio.new_event_loop()
    nest_asyncio.apply(loop)
    asyncio.set_event_loop(loop)
    loop.run_until_complete(supertokens_setup())
    loop.close()
    asyncio.set_event_loop_policy(_cur_event_loop_policy)
rishabhpoddar commented 4 months ago

Hey @virajkanwade thanks for the suggestion. We will work on this in a few weeks from now.

virajkanwade commented 4 months ago

@rishabhpoddar PR #502

sattvikc commented 4 months ago

@virajkanwade I think you should use the FastAPI's startup hook and call the async version of the create_or_update_tenant. It's not recommended to run sync variant in the ASGI environment.

@app.on_event("startup")
async def on_startup():
    await create_or_update_tenant(...)
virajkanwade commented 4 months ago

@sattvikc @app.on_event("startup") is deprecated, but I was able to get it to work with lifespan.

Regards