fix: also cleanup on asyncio cancel (#6586)

This commit is contained in:
Sarah Wooders
2025-12-09 16:27:00 -08:00
committed by Caren Thomas
parent b2cae07556
commit b23722e4a1

View File

@@ -1,3 +1,4 @@
import asyncio
import uuid
from contextlib import asynccontextmanager
from typing import AsyncGenerator
@@ -63,11 +64,22 @@ class DatabaseRegistry:
@asynccontextmanager
async def async_session(self) -> AsyncGenerator[AsyncSession, None]:
"""Get an async database session."""
"""Get an async database session.
Note: We explicitly handle asyncio.CancelledError separately because it's
a BaseException (not Exception) in Python 3.8+. Without this, cancelled
tasks would skip rollback() and return connections to the pool with
uncommitted transactions, causing "idle in transaction" connection leaks.
"""
async with async_session_factory() as session:
try:
yield session
await session.commit()
except asyncio.CancelledError:
# Task was cancelled (client disconnect, timeout, explicit cancellation)
# Must rollback to avoid returning connection with open transaction
await session.rollback()
raise
except Exception:
await session.rollback()
raise