Connection closing instantly with mongoengine 0.24 and pymongo >= 4.0
I am facing the following issue when trying to connect to my db using the last version of MongoEngine
I think it is due to this new behavior of pymongo 4 that does not automatically reconnects when you try to use a MongoClient whose connection was closed
Except I get it directly after calling connect, so the connection is not supposed to be close at this point, unless some code in connect closes the connection and is expecting MongoClient to automatically reconnect, as it would do in pymongo==3.12.3
mongo_engine_connection_dict = {
"db": os.environ["MONGODB_DATABASE"],
"host": os.environ["MONGODB_NETWORK_IP"],
"port": int(os.environ["MONGODB_PORT"]),
"username": os.environ["MONGODB_USERNAME"],
"password": os.environ["MONGODB_PASSWORD"],
"tls": os.environ["MONGODB_TLS"] == "true" if "MONGODB_TLS" in os.environ else True,
"tlsAllowInvalidCertificates": True,
"authentication_source": "admin",
}
connect(**mongo_engine_connection_dict)
doc=Document.objects.get(id=12)
Returns the error :
pymongo.errors.InvalidOperation: Cannot use MongoClient after close
This is weird, I'm not observing this but I'm also not using the tls options, did you find a workaround? Could you also try connecting with a uri (see here) to see if that makes a difference.
For what it's worth, I use the TLS options in my mongoengine configuration and I didn't observe this issue with pymongo 4, but I reverted back to pymongo 3.12 and haven't done much beyond a simple auth test. I'm never doing an explicit connect anywhere in my code. I think that's being done by flask-mongonegine.
@bagerard for now my solution was to revert to mongoengine==0.23.1 and pymongo==3.12.3
I'll give it a try with an uri and report here
@LuisBlanche I think you should also try to understand why the connection gets closed on the first place, perhaps look in the logs of your mongo instance
@bagerard yes I have tried this using the debugger and I think it is difficult to follow because of all the code around the concept of "alias" .. It is probably linked to the way the parameters are parsed and passed through to the pymongo.MongoClient object, but the thing is I don't get an Access Denied error , just is seems that the connection does not live to see the next line of code
Any updates on this one? Completely killed us out of the serverless game and is just painful to try to work through...@bagerard
It is probably related to the pymongo 4 upgrade, rather than mongoengine. Perhaps @ShaneHarvey (pymongo maintainer) can assist here ?
MongoClient only raises this error once it has been closed by an explicit call to client.close(). From a quick search it looks like the one and only place mongoengine calls close() is in connection.disconnect().
The only way to reproduce this error is for the app to acquire the client from connect() and then manually close it (which you should not do):
from mongoengine import *
mongo_engine_connection_dict = {
"db": "test",
"host": "localhost",
"port": 27017,
"username": "user",
"password": "password",
"tls": True,
"tlsAllowInvalidCertificates": True,
"authentication_source": "admin",
}
client = connect(**mongo_engine_connection_dict)
class User(Document):
name = StringField(max_length=50)
User.objects.filter(name="Nunu").first()
client.close()
User.objects.filter(name="Nunu").first() # Raises pymongo.errors.InvalidOperation: Cannot use MongoClient after close
One other way the app might be accidentally closing the client is by entering and exiting a with-statement (don't do this either):
with connect(**mongo_engine_connection_dict): # Client is automatically closed when exiting the with block.
User.objects.filter(name="Nunu").first()
User.objects.filter(name="Nunu").first() # Raises pymongo.errors.InvalidOperation: Cannot use MongoClient after close
You can use PDB to set a breakpoint on MongoClient.close to see where this is being called, like this:
$ python -m pdb repro-2627.py
> /Users/shane/git/mongoengine/repro-2627.py(1)<module>()
-> from mongoengine import *
(Pdb) from pymongo import MongoClient
(Pdb) b MongoClient.close
Breakpoint 1 at /Users/shane/mongoengine/.venv3.7/lib/python3.7/site-packages/pymongo/mongo_client.py:1142
(Pdb) c
> /Users/shane/mongoengine/.venv3.7/lib/python3.7/site-packages/pymongo/mongo_client.py(1157)close()
-> session_ids = self._topology.pop_all_sessions()
(Pdb) bt
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/bdb.py(578)run()
-> exec(cmd, globals, locals)
<string>(1)<module>()
/Users/shane/git/mongoengine/repro-2627.py(20)<module>()
-> client.close()
> /Users/shane/mongoengine/.venv3.7/lib/python3.7/site-packages/pymongo/mongo_client.py(1157)close()
-> session_ids = self._topology.pop_all_sessions()
(Pdb)
Any options how it can work with several calls of context manager?
Any options how it can work with several calls of context manager?
I don't follow. Can you show a short example of what you want to do?
Aha! I discovered the real problem here while working on another issue. Here's a short repro:
from mongoengine import *
from pymongo.errors import InvalidOperation
client1 = connect(alias='default')
client2 = connect(alias='non-default')
disconnect(alias='default')
try:
client1.admin.command('ping')
except InvalidOperation:
print('default client is closed')
try:
client2.admin.command('ping')
except InvalidOperation:
print('non-default client is also closed!')
The problem is that mongoengine will intentionally share a single MongoClient across multiple aliases if it determines the connection settings are equal (here https://github.com/MongoEngine/mongoengine/blob/4b5dbc7a52f95ae5525c08cee8ff9f743e8e677d/mongoengine/connection.py#L333-L334). The bug is that mongoengine does not remember this fact when disconnect() is called. So calling disconnect on one alias will close the client which might be used for others.
The fix is to skip calling MongoClient.close if this client instance is still in use by another alias. I'm working on the fix.
@LuisBlanche, @blochs, @bm13kk I believe I've fixed this issue here https://github.com/MongoEngine/mongoengine/pull/2703. Would you be able to test this change in your environment to confirm that it fixes the pymongo.errors.InvalidOperation: Cannot use MongoClient after close bug?
To install the fix:
python -m pip install https://github.com/ShaneHarvey/mongoengine/archive/refs/heads/fix-disconnect-closes-clients-too-early.zip
So I hate to reopen stuff....but I'm still getting it.
@blochsbek, could you please open a new issue with python version, pip list output, repro code, the error traceback, and any other relevant info (like does your app call client.close or disconnect)?
@ShaneHarvey Looks to be user error. Trying to access a cursor outside of a context manager, which will definitely do it.