Skip to content

Commit b402239

Browse files
authored
PYTHON-5219 - Avoid awaiting coroutines when holding locks (#2250)
1 parent 8b66889 commit b402239

File tree

4 files changed

+32
-18
lines changed

4 files changed

+32
-18
lines changed

pymongo/asynchronous/pool.py

+16-7
Original file line numberDiff line numberDiff line change
@@ -931,13 +931,15 @@ async def remove_stale_sockets(self, reference_generation: int) -> None:
931931
return
932932

933933
if self.opts.max_idle_time_seconds is not None:
934+
close_conns = []
934935
async with self.lock:
935936
while (
936937
self.conns
937938
and self.conns[-1].idle_time_seconds() > self.opts.max_idle_time_seconds
938939
):
939-
conn = self.conns.pop()
940-
await conn.close_conn(ConnectionClosedReason.IDLE)
940+
close_conns.append(self.conns.pop())
941+
for conn in close_conns:
942+
await conn.close_conn(ConnectionClosedReason.IDLE)
941943

942944
while True:
943945
async with self.size_cond:
@@ -957,14 +959,18 @@ async def remove_stale_sockets(self, reference_generation: int) -> None:
957959
self._pending += 1
958960
incremented = True
959961
conn = await self.connect()
962+
close_conn = False
960963
async with self.lock:
961964
# Close connection and return if the pool was reset during
962965
# socket creation or while acquiring the pool lock.
963966
if self.gen.get_overall() != reference_generation:
964-
await conn.close_conn(ConnectionClosedReason.STALE)
965-
return
966-
self.conns.appendleft(conn)
967-
self.active_contexts.discard(conn.cancel_context)
967+
close_conn = True
968+
if not close_conn:
969+
self.conns.appendleft(conn)
970+
self.active_contexts.discard(conn.cancel_context)
971+
if close_conn:
972+
await conn.close_conn(ConnectionClosedReason.STALE)
973+
return
968974
finally:
969975
if incremented:
970976
# Notify after adding the socket to the pool.
@@ -1343,17 +1349,20 @@ async def checkin(self, conn: AsyncConnection) -> None:
13431349
error=ConnectionClosedReason.ERROR,
13441350
)
13451351
else:
1352+
close_conn = False
13461353
async with self.lock:
13471354
# Hold the lock to ensure this section does not race with
13481355
# Pool.reset().
13491356
if self.stale_generation(conn.generation, conn.service_id):
1350-
await conn.close_conn(ConnectionClosedReason.STALE)
1357+
close_conn = True
13511358
else:
13521359
conn.update_last_checkin_time()
13531360
conn.update_is_writable(bool(self.is_writable))
13541361
self.conns.appendleft(conn)
13551362
# Notify any threads waiting to create a connection.
13561363
self._max_connecting_cond.notify()
1364+
if close_conn:
1365+
await conn.close_conn(ConnectionClosedReason.STALE)
13571366

13581367
async with self.size_cond:
13591368
if txn:

pymongo/asynchronous/topology.py

-2
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,6 @@ async def open(self) -> None:
244244
# Close servers and clear the pools.
245245
for server in self._servers.values():
246246
await server.close()
247-
if not _IS_SYNC:
248-
self._monitor_tasks.append(server._monitor)
249247
# Reset the session pool to avoid duplicate sessions in
250248
# the child process.
251249
self._session_pool.reset()

pymongo/synchronous/pool.py

+16-7
Original file line numberDiff line numberDiff line change
@@ -927,13 +927,15 @@ def remove_stale_sockets(self, reference_generation: int) -> None:
927927
return
928928

929929
if self.opts.max_idle_time_seconds is not None:
930+
close_conns = []
930931
with self.lock:
931932
while (
932933
self.conns
933934
and self.conns[-1].idle_time_seconds() > self.opts.max_idle_time_seconds
934935
):
935-
conn = self.conns.pop()
936-
conn.close_conn(ConnectionClosedReason.IDLE)
936+
close_conns.append(self.conns.pop())
937+
for conn in close_conns:
938+
conn.close_conn(ConnectionClosedReason.IDLE)
937939

938940
while True:
939941
with self.size_cond:
@@ -953,14 +955,18 @@ def remove_stale_sockets(self, reference_generation: int) -> None:
953955
self._pending += 1
954956
incremented = True
955957
conn = self.connect()
958+
close_conn = False
956959
with self.lock:
957960
# Close connection and return if the pool was reset during
958961
# socket creation or while acquiring the pool lock.
959962
if self.gen.get_overall() != reference_generation:
960-
conn.close_conn(ConnectionClosedReason.STALE)
961-
return
962-
self.conns.appendleft(conn)
963-
self.active_contexts.discard(conn.cancel_context)
963+
close_conn = True
964+
if not close_conn:
965+
self.conns.appendleft(conn)
966+
self.active_contexts.discard(conn.cancel_context)
967+
if close_conn:
968+
conn.close_conn(ConnectionClosedReason.STALE)
969+
return
964970
finally:
965971
if incremented:
966972
# Notify after adding the socket to the pool.
@@ -1339,17 +1345,20 @@ def checkin(self, conn: Connection) -> None:
13391345
error=ConnectionClosedReason.ERROR,
13401346
)
13411347
else:
1348+
close_conn = False
13421349
with self.lock:
13431350
# Hold the lock to ensure this section does not race with
13441351
# Pool.reset().
13451352
if self.stale_generation(conn.generation, conn.service_id):
1346-
conn.close_conn(ConnectionClosedReason.STALE)
1353+
close_conn = True
13471354
else:
13481355
conn.update_last_checkin_time()
13491356
conn.update_is_writable(bool(self.is_writable))
13501357
self.conns.appendleft(conn)
13511358
# Notify any threads waiting to create a connection.
13521359
self._max_connecting_cond.notify()
1360+
if close_conn:
1361+
conn.close_conn(ConnectionClosedReason.STALE)
13531362

13541363
with self.size_cond:
13551364
if txn:

pymongo/synchronous/topology.py

-2
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,6 @@ def open(self) -> None:
244244
# Close servers and clear the pools.
245245
for server in self._servers.values():
246246
server.close()
247-
if not _IS_SYNC:
248-
self._monitor_tasks.append(server._monitor)
249247
# Reset the session pool to avoid duplicate sessions in
250248
# the child process.
251249
self._session_pool.reset()

0 commit comments

Comments
 (0)