--- /dev/null
+.. change::
+ :tags: bug, asyncio
+ :tickets: 8145
+
+ Added ``asyncio.shield()`` to the connection and session release process
+ specifically within the ``__aexit__()`` context manager exit, when using
+ :class:`.AsyncConnection` or :class:`.AsyncSession` as a context manager
+ that releases the object when the context manager is complete. This appears
+ to help with task cancellation when using alternate concurrency libraries
+ such as ``anyio``, ``uvloop`` that otherwise don't provide an async context
+ for the connection pool to release the connection properly during task
+ cancellation.
+
+
# the MIT License: https://www.opensource.org/licenses/mit-license.php
from __future__ import annotations
+import asyncio
from typing import Any
from typing import Dict
from typing import Generator
return self.start().__await__()
async def __aexit__(self, type_: Any, value: Any, traceback: Any) -> None:
- await self.close()
+ await asyncio.shield(self.close())
# START PROXY METHODS AsyncConnection
async def __aexit__(
self, type_: Any, value: Any, traceback: Any
) -> None:
- await self.transaction.__aexit__(type_, value, traceback)
- await self.conn.close()
+ async def go() -> None:
+ await self.transaction.__aexit__(type_, value, traceback)
+ await self.conn.close()
+
+ await asyncio.shield(go())
def __init__(self, sync_engine: Engine):
if not sync_engine.dialect.is_async:
"""
- return await greenlet_spawn(self.sync_engine.dispose, close=close)
+ await greenlet_spawn(self.sync_engine.dispose, close=close)
# START PROXY METHODS AsyncEngine
# the MIT License: https://www.opensource.org/licenses/mit-license.php
from __future__ import annotations
+import asyncio
from typing import Any
from typing import Dict
from typing import Generic
:meth:`_asyncio.AsyncSession.close`
"""
- return await greenlet_spawn(self.sync_session.close)
+ await greenlet_spawn(self.sync_session.close)
async def invalidate(self) -> None:
"""Close this Session, using connection invalidation.
return self
async def __aexit__(self, type_: Any, value: Any, traceback: Any) -> None:
- await self.close()
+ await asyncio.shield(self.close())
def _maker_context_manager(self: _AS) -> _AsyncSessionContextManager[_AS]:
return _AsyncSessionContextManager(self)
return self.async_session
async def __aexit__(self, type_: Any, value: Any, traceback: Any) -> None:
- await self.trans.__aexit__(type_, value, traceback)
- await self.async_session.__aexit__(type_, value, traceback)
+ async def go() -> None:
+ await self.trans.__aexit__(type_, value, traceback)
+ await self.async_session.__aexit__(type_, value, traceback)
+
+ await asyncio.shield(go())
class AsyncSessionTransaction(