-
First Check
Commit to Help
Example Code# mongo
from motor import motor_asyncio
mongo_uri = "mongodb://mongoUser:***/?authSource=admin"
mongo_client = motor_asyncio.AsyncIOMotorClient(mongo_uri)
def get_users_db() -> motor_asyncio.AsyncIOMotorDatabase:
return mongo_client.devdb
# user_routes
import fastapi
import mongo
from bson import objectid
db = mongo.get_users_db()
router = fastapi.APIRouter()
@router.get("/{user_id}")
async def get_user_by_id(user_id: str):
user = await db.users.find_one({"_id": objectid.ObjectId(user_id)})
if user:
user["_id"] = str(user["_id"])
return user
return {"error": "no user found"}
# main.py
import fastapi
import user_routes
app = fastapi.FastAPI()
app.include_router(user_routes.router) Descriptioni am trying to create an app with mongodb client
Operating SystemLinux Operating System DetailsDebian 11 FastAPI Version0.68.1 Python VersionPython 3.9.2 Additional Contextmotor==2.2.6 this issue only happens with gunicorn as server and only when accessing mongodb from a fastapi route (i checked running db query in the mongo file and it works) this my first ever time creating an issue, so please guide me i did something wrong. |
Beta Was this translation helpful? Give feedback.
Replies: 10 comments
-
This is a quite common issue when using Motor (unfortunately, their implementation doesn't always play well with some event loops patterns). I think the problem comes from here: def get_users_db() -> motor_asyncio.AsyncIOMotorDatabase:
return mongo_client.devdb I'm not really sure about Motor implements this underneath, but I guess it will give you different instances for the same database ; which may be attached to a different event loop. Maybe try something like this: from motor import motor_asyncio
mongo_uri = "mongodb://mongoUser:***/?authSource=admin"
mongo_client = motor_asyncio.AsyncIOMotorClient(mongo_uri)
users_db = mongo_client.devdb
def get_users_db() -> motor_asyncio.AsyncIOMotorDatabase:
return users_db |
Beta Was this translation helpful? Give feedback.
-
You should init Motor client as a startup event |
Beta Was this translation helpful? Give feedback.
-
thanks @frankie567 and @DavidBord for taking a look into this problem. solution by @frankie567 produces the same error, that is motor gets attached to a different loop than fastapi. This problem appears to be in newer version of either motor, gunicorn or fastapi as initializing motor outside startup was working fine prevesouly, also it works if I use uvicorn as a server instead of gunicorn (i don't know which one is better, i use gunicorn only because that is suggested in fastapi and uvicorn docs) This might not be the place to ask, but can you suggest how to handle refrence to mongodb client or db when we init motor in app's startup event (using request.app.client seems unmanageable). Any help/pointer would be nice |
Beta Was this translation helpful? Give feedback.
-
The problem is with |
Beta Was this translation helpful? Give feedback.
-
@xcoder01 the startup event handler inits |
Beta Was this translation helpful? Give feedback.
-
you should define in start up , like this : app = FastAPI()
app.add_event_handler("startup", start_app)
async def start_app():
await Mongo().get_connection()
from motor.motor_asyncio import AsyncIOMotorClient
from config import CONNECTION_STRING, DB_NAME
class Mongo:
client = None
db = None
async def get_connection(self) -> AsyncIOMotorClient:
if not Mongo.client:
Mongo.client = AsyncIOMotorClient(CONNECTION_STRING) now you can use mongo client every where you want!!! |
Beta Was this translation helpful? Give feedback.
-
I have the same problem but only for the tests which are running under pytest. The app under uvicorn works fine. The problem appears when I switch from fastapi 0.68.x to 0.69.x or higher. It seems that the motor event loop isn't initialized properly in the tests print(asyncio.get_event_loop(), db.client.io_loop) under pytest: print(asyncio.get_event_loop(), db.client.io_loop) under uvicorn: I think it has to do with the breaking change introduced in 0.69.0:
motor isn't for some reason using the existing event loop and might created it's own hence I get
I tried also |
Beta Was this translation helpful? Give feedback.
-
That is the problem: encode/starlette#1315
works for me |
Beta Was this translation helpful? Give feedback.
-
@CanD42 I was facing this using fastapi + fsspec's adlfs and solved the same way. Thanks
|
Beta Was this translation helpful? Give feedback.
-
Thanks for the help here everyone! 👏 🙇 Thanks for reporting back and closing the issue @xcoder01 👍 |
Beta Was this translation helpful? Give feedback.
You should init Motor client as a startup event