Skip to content

Commit de94fd1

Browse files
authored
Merge pull request #2716 from bagerard/ShaneHarvey-fix-disconnect-closes-clients-too-early
Clone - Shane harvey fix disconnect closes clients too early
2 parents 8d23ed9 + f9b6218 commit de94fd1

File tree

3 files changed

+40
-4
lines changed

3 files changed

+40
-4
lines changed

docs/changelog.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Development
1111
- Turning off dereferencing for the results of distinct query. #2663
1212
- Add tests against Mongo 5.0 in pipeline
1313
- Drop support for Python 3.6 (EOL)
14+
- Bug fix support for PyMongo>=4 to fix "InvalidOperation: Cannot use MongoClient after close"
15+
errors.
1416

1517
Changes in 0.24.2
1618
=================

mongoengine/connection.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,9 +246,15 @@ def disconnect(alias=DEFAULT_CONNECTION_NAME):
246246
from mongoengine import Document
247247
from mongoengine.base.common import _get_documents_by_db
248248

249-
if alias in _connections:
250-
get_connection(alias=alias).close()
251-
del _connections[alias]
249+
connection = _connections.pop(alias, None)
250+
if connection:
251+
# MongoEngine may share the same MongoClient across multiple aliases
252+
# if connection settings are the same so we only close
253+
# the client if we're removing the final reference.
254+
# Important to use 'is' instead of '==' because clients connected to the same cluster
255+
# will compare equal even with different options
256+
if all(connection is not c for c in _connections.values()):
257+
connection.close()
252258

253259
if alias in _dbs:
254260
# Detach all cached collections in Documents

tests/test_connection.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
import pytest
66
from bson.tz_util import utc
77
from pymongo import MongoClient, ReadPreference
8-
from pymongo.errors import InvalidName, OperationFailure
8+
from pymongo.errors import (
9+
InvalidName,
10+
InvalidOperation,
11+
OperationFailure,
12+
)
913

1014
import mongoengine.connection
1115
from mongoengine import (
@@ -287,6 +291,30 @@ def test_disconnect_silently_pass_if_alias_does_not_exist(self):
287291
assert len(connections) == 0
288292
disconnect(alias="not_exist")
289293

294+
def test_disconnect_does_not_close_client_used_by_another_alias(self):
295+
client1 = connect(alias="disconnect_reused_client_test_1")
296+
client2 = connect(alias="disconnect_reused_client_test_2")
297+
client3 = connect(alias="disconnect_reused_client_test_3", maxPoolSize=10)
298+
assert client1 is client2
299+
assert client1 is not client3
300+
client1.admin.command("ping")
301+
disconnect("disconnect_reused_client_test_1")
302+
# The client is not closed because the second alias still exists.
303+
client2.admin.command("ping")
304+
disconnect("disconnect_reused_client_test_2")
305+
# The client is now closed:
306+
if PYMONGO_VERSION >= (4,):
307+
with pytest.raises(InvalidOperation):
308+
client2.admin.command("ping")
309+
# 3rd client connected to the same cluster with different options
310+
# is not closed either.
311+
client3.admin.command("ping")
312+
disconnect("disconnect_reused_client_test_3")
313+
# 3rd client is now closed:
314+
if PYMONGO_VERSION >= (4,):
315+
with pytest.raises(InvalidOperation):
316+
client3.admin.command("ping")
317+
290318
def test_disconnect_all(self):
291319
connections = mongoengine.connection._connections
292320
dbs = mongoengine.connection._dbs

0 commit comments

Comments
 (0)