Hi All,
I am having the same issue as Rabindra as of his last post (i.e. searching for working Python implementation of the proposed solution).
The first block below is the code I am using (minus MongoDB Atlas credentials). I initially tried this using PyMongo[srv] 3.12.3 and Motor 2.5.1, and then using PyMongo[srv] 3.10.1 and Motor 2.1.0, as Shane suggested.
Using POSTMAN, in either case, I can get a “hello world” response from the GET route, but not an MongoDB insertion or the find method from the POST route, for which I instead get a JSON message “{“message”: “Endpoint request timed out”}”, and the CloudWatch log file (2nd & 3rd blocks) for this can be seen below my Python code. (Notably, this same POST route (and the GET) works as expected when hosting this code locally with uvicorn.)
from __future__ import annotations
from imp import reload
import os
from typing import Optional
from datetime import datetime
from fastapi import FastAPI, Body, HTTPException, status
from fastapi.responses import JSONResponse
from fastapi.encoders import jsonable_encoder
from bson import ObjectId
from pydantic import BaseModel, Field, EmailStr
import motor.motor_asyncio
from mangum import Mangum
app = FastAPI()
# client = motor.motor_asyncio.AsyncIOMotorClient(os.environ["MONGODB_URL"])
client = motor.motor_asyncio.AsyncIOMotorClient('mongodb+srv://USERNAME:PASSWORD@URL.mongodb.net/myFirstDatabase?retryWrites=true&w=majority')
db = client['test']
# both classes below based on https://www.mongodb.com/developer/quickstart/python-quickstart-fastapi/
class PyObjectId(ObjectId): # so FastAPI can encode ObjectID as JSON
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, v):
if not ObjectId.is_valid(v):
raise ValueError("Invalid objectid")
return ObjectId(v)
@classmethod
def __modify_schema__(cls, field_schema):
field_schema.update(type="string")
class FlexyDataInsertion(BaseModel):
id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
dataSeries_id: str = Field(...)
timestamp: datetime = Field(...)
value: int = Field(...)
class Config:
allow_population_by_field_name = True
arbitrary_types_allowed = True
json_encoders = {ObjectId: str}
schema_extra = {
"example": {
"dataSeries_id": "blah",
"timestamp": "2022-03-24T08:48:57Z",
"value": 26,
}
}
@app.post('/dataPoints', response_description="Add data point(s)", response_model=None, tags=["insertion"])
async def add_data_point(datapoint: FlexyDataInsertion = Body(...)) -> None:
datapoint = jsonable_encoder(datapoint)
new_data = await db['test/dataSeries_SENSOR_Humidity/dataPoints'].insert_one(datapoint)
created_data = await db['test/dataSeries_SENSOR_Humidity/dataPoints'].find_one({"_id": new_data.inserted_id})
return JSONResponse(content=created_data)
@app.get('/dataPoints', response_model=None, tags=["extraction"])
async def retrieve_data_point():
return JSONResponse("hello world")
handler = Mangum(app=app)
# uncomment for running on localhost server, not in production
# import uvicorn
# if __name__ == "__main__":
# uvicorn.run("app:app", host="127.0.0.1", port=8000, log_level="info", reload=True)
.
Error message from CloudWatch (part of MongoDB URL redacted using “XXXXXXXXXXX”):
[ERROR] 2022-04-09T02:49:34.716Z fb7adf6d-f52b-42d5-bd34-72f4fc3bc7b4 An error occurred running the application.
Traceback (most recent call last):
File "/var/task/mangum/protocols/http.py", line 66, in run
await app(self.scope, self.receive, self.send)
File "/var/task/fastapi/applications.py", line 261, in __call__
await super().__call__(scope, receive, send)
File "/var/task/starlette/applications.py", line 112, in __call__
await self.middleware_stack(scope, receive, send)
File "/var/task/starlette/middleware/errors.py", line 181, in __call__
raise exc
File "/var/task/starlette/middleware/errors.py", line 159, in __call__
await self.app(scope, receive, _send)
File "/var/task/starlette/exceptions.py", line 82, in __call__
raise exc
File "/var/task/starlette/exceptions.py", line 71, in __call__
await self.app(scope, receive, sender)
File "/var/task/fastapi/middleware/asyncexitstack.py", line 21, in __call__
raise e
File "/var/task/fastapi/middleware/asyncexitstack.py", line 18, in __call__
await self.app(scope, receive, send)
File "/var/task/starlette/routing.py", line 656, in __call__
await route.handle(scope, receive, send)
File "/var/task/starlette/routing.py", line 259, in handle
await self.app(scope, receive, send)
File "/var/task/starlette/routing.py", line 61, in app
response = await func(request)
File "/var/task/fastapi/routing.py", line 227, in app
raw_response = await run_endpoint_function(
File "/var/task/fastapi/routing.py", line 160, in run_endpoint_function
return await dependant.call(**values)
File "/var/task/app.py", line 97, in add_data_point
new_data = await db['test/dataSeries_SENSOR_Humidity/dataPoints'].insert_one(datapoint)
File "/var/lang/lib/python3.8/concurrent/futures/thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "/var/task/pymongo/collection.py", line 695, in insert_one
self._insert(document,
File "/var/task/pymongo/collection.py", line 610, in _insert
return self._insert_one(
File "/var/task/pymongo/collection.py", line 599, in _insert_one
self.__database.client._retryable_write(
File "/var/task/pymongo/mongo_client.py", line 1490, in _retryable_write
with self._tmp_session(session) as s:
File "/var/lang/lib/python3.8/contextlib.py", line 113, in __enter__
return next(self.gen)
File "/var/task/pymongo/mongo_client.py", line 1823, in _tmp_session
s = self._ensure_session(session)
File "/var/task/pymongo/mongo_client.py", line 1810, in _ensure_session
return self.__start_session(True, causal_consistency=False)
File "/var/task/pymongo/mongo_client.py", line 1763, in __start_session
server_session = self._get_server_session()
File "/var/task/pymongo/mongo_client.py", line 1796, in _get_server_session
return self._topology.get_server_session()
File "/var/task/pymongo/topology.py", line 487, in get_server_session
self._select_servers_loop(
File "/var/task/pymongo/topology.py", line 208, in _select_servers_loop
raise ServerSelectionTimeoutError(
pymongo.errors.ServerSelectionTimeoutError: connection closed,connection closed,connection closed
[ERROR] 2022-04-09T02:49:34.716Z fb7adf6d-f52b-42d5-bd34-72f4fc3bc7b4 An error occurred running the application. Traceback (most recent call last): File "/var/task/mangum/protocols/http.py", line 66, in run await app(self.scope, self.receive, self.send) File "/var/task/fastapi/applications.py", line 261, in __call__ await super().__call__(scope, receive, send) File "/var/task/starlette/applications.py", line 112, in __call__ await self.middleware_stack(scope, receive, send) File "/var/task/starlette/middleware/errors.py", line 181, in __call__ raise exc File "/var/task/starlette/middleware/errors.py", line 159, in __call__ await self.app(scope, receive, _send) File "/var/task/starlette/exceptions.py", line 82, in __call__ raise exc File "/var/task/starlette/exceptions.py", line 71, in __call__ await self.app(scope, receive, sender) File "/var/task/fastapi/middleware/asyncexitstack.py", line 21, in __call__ raise e File "/var/task/fastapi/middleware/asyncexitstack.py", line 18, in __call__ await self.app(scope, receive, send) File "/var/task/starlette/routing.py", line 656, in __call__ await route.handle(scope, receive, send) File "/var/task/starlette/routing.py", line 259, in handle await self.app(scope, receive, send) File "/var/task/starlette/routing.py", line 61, in app response = await func(request) File "/var/task/fastapi/routing.py", line 227, in app raw_response = await run_endpoint_function( File "/var/task/fastapi/routing.py", line 160, in run_endpoint_function return await dependant.call(**values) File "/var/task/app.py", line 97, in add_data_point new_data = await db['test/dataSeries_SENSOR_Humidity/dataPoints'].insert_one(datapoint) File "/var/lang/lib/python3.8/concurrent/futures/thread.py", line 57, in run result = self.fn(*self.args, **self.kwargs) File "/var/task/pymongo/collection.py", line 695, in insert_one self._insert(document, File "/var/task/pymongo/collection.py", line 610, in _insert return self._insert_one( File "/var/task/pymongo/collection.py", line 599, in _insert_one self.__database.client._retryable_write( File "/var/task/pymongo/mongo_client.py", line 1490, in _retryable_write with self._tmp_session(session) as s: File "/var/lang/lib/python3.8/contextlib.py", line 113, in __enter__ return next(self.gen) File "/var/task/pymongo/mongo_client.py", line 1823, in _tmp_session s = self._ensure_session(session) File "/var/task/pymongo/mongo_client.py", line 1810, in _ensure_session return self.__start_session(True, causal_consistency=False) File "/var/task/pymongo/mongo_client.py", line 1763, in __start_session server_session = self._get_server_session() File "/var/task/pymongo/mongo_client.py", line 1796, in _get_server_session return self._topology.get_server_session() File "/var/task/pymongo/topology.py", line 487, in get_server_session self._select_servers_loop( File "/var/task/pymongo/topology.py", line 208, in _select_servers_loop raise ServerSelectionTimeoutError( pymongo.errors.ServerSelectionTimeoutError: connection closed,connection closed,connection closed
.
With the latest Motor and Pymongo versions, there is the following additional 2 lines (session_timeout & _check_session_support) in the error log, near the end:
session_timeout = self._check_session_support()
File "/var/task/pymongo/topology.py", line 504, in _check_session_support
self._select_servers_loop(
File "/var/task/pymongo/topology.py", line 218, in _select_servers_loop
raise ServerSelectionTimeoutError(
pymongo.errors.ServerSelectionTimeoutError: connection closed,connection closed,connection closed, Timeout: 30s, Topology Description: <TopologyDescription id: 6250e075e1229bd047cf86b7, topology_type: ReplicaSetNoPrimary, servers: [<ServerDescription ('XXXXXXXXXXX.mongodb.net', 27017) server_type: Unknown, rtt: None, error=AutoReconnect('connection closed')>, <ServerDescription ('XXXXXXXXXXX.mongodb.net', 27017) server_type: Unknown, rtt: None, error=AutoReconnect('connection closed')>, <ServerDescription ('XXXXXXXXXXX.mongodb.net', 27017) server_type: Unknown, rtt: None, error=AutoReconnect('connection closed')>]>
[ERROR] 2022-04-09T01:32:20.565Z c1103461-149b-4eed-92d2-013b500fceaf An error occurred running the application. Traceback (most recent call last): File "/var/task/mangum/protocols/http.py", line 66, in run await app(self.scope, self.receive, self.send) File "/var/task/fastapi/applications.py", line 261, in __call__ await super().__call__(scope, receive, send) File "/var/task/starlette/applications.py", line 112, in __call__ await self.middleware_stack(scope, receive, send) File "/var/task/starlette/middleware/errors.py", line 181, in __call__ raise exc File "/var/task/starlette/middleware/errors.py", line 159, in __call__ await self.app(scope, receive, _send) File "/var/task/starlette/exceptions.py", line 82, in __call__ raise exc File "/var/task/starlette/exceptions.py", line 71, in __call__ await self.app(scope, receive, sender) File "/var/task/fastapi/middleware/asyncexitstack.py", line 21, in __call__ raise e File "/var/task/fastapi/middleware/asyncexitstack.py", line 18, in __call__ await self.app(scope, receive, send) File "/var/task/starlette/routing.py", line 656, in __call__ await route.handle(scope, receive, send) File "/var/task/starlette/routing.py", line 259, in handle await self.app(scope, receive, send) File "/var/task/starlette/routing.py", line 61, in app response = await func(request) File "/var/task/fastapi/routing.py", line 227, in app raw_response = await run_endpoint_function( File "/var/task/fastapi/routing.py", line 160, in run_endpoint_function return await dependant.call(**values) File "/var/task/app.py", line 96, in add_data_point new_data = await db['test/dataSeries_SENSOR_Humidity/dataPoints'].insert_one(datapoint) File "/var/lang/lib/python3.8/concurrent/futures/thread.py", line 57, in run result = self.fn(*self.args, **self.kwargs) File "/var/task/pymongo/collection.py", line 705, in insert_one self._insert(document, File "/var/task/pymongo/collection.py", line 620, in _insert return self._insert_one( File "/var/task/pymongo/collection.py", line 609, in _insert_one self.__database.client._retryable_write( File "/var/task/pymongo/mongo_client.py", line 1551, in _retryable_write with self._tmp_session(session) as s: File "/var/lang/lib/python3.8/contextlib.py", line 113, in __enter__ return next(self.gen) File "/var/task/pymongo/mongo_client.py", line 1948, in _tmp_session s = self._ensure_session(session) File "/var/task/pymongo/mongo_client.py", line 1935, in _ensure_session return self.__start_session(True, causal_consistency=False) File "/var/task/pymongo/mongo_client.py", line 1883, in __start_session server_session = self._get_server_session() File "/var/task/pymongo/mongo_client.py", line 1921, in _get_server_session return self._topology.get_server_session() File "/var/task/pymongo/topology.py", line 520, in get_server_session session_timeout = self._check_session_support() File "/var/task/pymongo/topology.py", line 504, in _check_session_support self._select_servers_loop( File "/var/task/pymongo/topology.py", line 218, in _select_servers_loop raise ServerSelectionTimeoutError( pymongo.errors.ServerSelectionTimeoutError: connection closed,connection closed,connection closed, Timeout: 30s, Topology Description: <TopologyDescription id: 6250e075e1229bd047cf86b7, topology_type: ReplicaSetNoPrimary, servers: [<ServerDescription ('XXXXXXXXXXX.mongodb.net', 27017) server_type: Unknown, rtt: None, error=AutoReconnect('connection closed')>, <ServerDescription ('XXXXXXXXXXX.mongodb.net', 27017) server_type: Unknown, rtt: None, error=AutoReconnect('connection closed')>, <ServerDescription ('XXXXXXXXXXX.mongodb.net', 27017) server_type: Unknown, rtt: None, error=AutoReconnect('connection closed')>]>