merge testing->tomerge/main #7
@@ -40,28 +40,26 @@ _log = get_logger("db.pool")
|
|||||||
async def _force_close(session: AsyncSession) -> None:
|
async def _force_close(session: AsyncSession) -> None:
|
||||||
"""Close a session, forcing connection invalidation if clean close fails.
|
"""Close a session, forcing connection invalidation if clean close fails.
|
||||||
|
|
||||||
Shielded from cancellation and catches every exception class including
|
Under cancellation, ``session.close()`` may try to issue a ROLLBACK on
|
||||||
CancelledError. If session.close() fails (corrupted connection), we
|
a connection that was interrupted mid-query — aiomysql then raises
|
||||||
invalidate the underlying connection so the pool discards it entirely
|
``InterfaceError("Cancelled during execution")`` and the connection is
|
||||||
rather than leaving it checked-out forever.
|
left checked-out, reported by the pool as ``non-checked-in connection``
|
||||||
|
on GC. When clean close fails, invalidate the session's connections
|
||||||
|
directly (no I/O, just flips the pool record) so the pool discards
|
||||||
|
them immediately instead of waiting for garbage collection.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
await asyncio.shield(session.close())
|
await asyncio.shield(session.close())
|
||||||
|
return
|
||||||
except BaseException:
|
except BaseException:
|
||||||
# close() failed — connection is likely corrupted.
|
pass
|
||||||
# Try to invalidate the raw connection so the pool drops it.
|
|
||||||
try:
|
try:
|
||||||
bind = session.get_bind()
|
# invalidate() is sync and does no network I/O — safe inside a
|
||||||
if hasattr(bind, "dispose"):
|
# cancelled task. Tells the pool to drop the underlying DBAPI
|
||||||
pass # don't dispose the whole engine
|
# connection rather than return it for reuse.
|
||||||
# The sync_session holds the connection record; invalidating
|
session.sync_session.invalidate()
|
||||||
# it tells the pool to discard rather than reuse.
|
|
||||||
sync = session.sync_session
|
|
||||||
if sync.is_active:
|
|
||||||
sync.rollback()
|
|
||||||
sync.close()
|
|
||||||
except BaseException:
|
except BaseException:
|
||||||
_log.debug("force-close: fallback cleanup failed", exc_info=True)
|
_log.debug("force-close: invalidate failed", exc_info=True)
|
||||||
|
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
|
|||||||
Reference in New Issue
Block a user