Skip to content

Commit b69f8d4

Browse files
Shield _release_reservation in acquire's create-connection failure paths
The new-slot reservation arm and the dead-conn replacement arm both ran ``await self._release_reservation()`` un- shielded after ``_create_connection`` raised. Outer cancel re-arming on the await checkpoint would bypass the decrement; each cancel-mid-create leaked one ``_size`` slot and pools eventually wedged at ``max_size`` with no checked- out connections. Mirrors the existing ``await asyncio.shield(self._release_reservation())`` discipline in ``_drain_idle`` failure paths and in the sibling ``_release`` cleanup. ``contextlib.suppress (asyncio.CancelledError)`` absorbs the cancel acknowledgment so the original exception (the one that brought us into the except arm) is what propagates via ``raise``. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent b70264a commit b69f8d4

1 file changed

Lines changed: 15 additions & 2 deletions

File tree

src/dqliteclient/pool.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,16 @@ async def acquire(self) -> AsyncIterator[DqliteConnection]:
794794
try:
795795
conn = await self._create_connection()
796796
except BaseException:
797-
await self._release_reservation()
797+
# Shield the release so an outer cancel re-arming
798+
# on the await checkpoint does not bypass the
799+
# decrement; without the shield, each
800+
# cancel-mid-create leaks one ``_size`` slot and
801+
# the pool eventually wedges at max_size with no
802+
# checked-out connections. Mirrors the existing
803+
# ``await asyncio.shield(self._release_reservation())``
804+
# in ``_drain_idle`` failure paths.
805+
with contextlib.suppress(asyncio.CancelledError):
806+
await asyncio.shield(self._release_reservation())
798807
raise
799808
break
800809

@@ -973,7 +982,11 @@ async def acquire(self) -> AsyncIterator[DqliteConnection]:
973982
try:
974983
conn = await self._create_connection()
975984
except BaseException:
976-
await self._release_reservation()
985+
# Same shielded-release rationale as the new-slot
986+
# arm above: outer cancel re-arming on the create-
987+
# connection await must not bypass the decrement.
988+
with contextlib.suppress(asyncio.CancelledError):
989+
await asyncio.shield(self._release_reservation())
977990
raise
978991
# close() may have run while _create_connection was
979992
# suspended on leader discovery / TCP handshake. Without

0 commit comments

Comments
 (0)