]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
add shield() in aexit
authorFederico Caselli <cfederico87@gmail.com>
Fri, 17 Jun 2022 21:12:39 +0000 (23:12 +0200)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 18 Jul 2022 15:36:37 +0000 (11:36 -0400)
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.

Fixes: #8145
Change-Id: I0b1ea9c3a22a18619341cbb8591225fcd339042c
(cherry picked from commit 1acaf0b2e4859a274e753b5054dcde3d5c7ca10e)

doc/build/changelog/unreleased_14/8145.rst [new file with mode: 0644]
lib/sqlalchemy/ext/asyncio/engine.py
lib/sqlalchemy/ext/asyncio/session.py

diff --git a/doc/build/changelog/unreleased_14/8145.rst b/doc/build/changelog/unreleased_14/8145.rst
new file mode 100644 (file)
index 0000000..4cd6c12
--- /dev/null
@@ -0,0 +1,14 @@
+.. 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.
+
+
index 63d148c9757baa508325ce10f4f681a9a286bc87..4fbe4f7a592cc0fac0469dab7d0ef9842fc658e0 100644 (file)
@@ -4,6 +4,8 @@
 #
 # This module is part of SQLAlchemy and is released under
 # the MIT License: https://www.opensource.org/licenses/mit-license.php
+import asyncio
+
 from . import exc as async_exc
 from .base import ProxyComparable
 from .base import StartableContext
@@ -549,7 +551,7 @@ class AsyncConnection(ProxyComparable, StartableContext, AsyncConnectable):
         return self.start().__await__()
 
     async def __aexit__(self, type_, value, traceback):
-        await self.close()
+        await asyncio.shield(self.close())
 
 
 @util.create_proxy_methods(
@@ -600,8 +602,11 @@ class AsyncEngine(ProxyComparable, AsyncConnectable):
             return self.conn
 
         async def __aexit__(self, type_, value, traceback):
-            await self.transaction.__aexit__(type_, value, traceback)
-            await self.conn.close()
+            async def go():
+                await self.transaction.__aexit__(type_, value, traceback)
+                await self.conn.close()
+
+            await asyncio.shield(go())
 
     def __init__(self, sync_engine):
         if not sync_engine.dialect.is_async:
@@ -698,7 +703,7 @@ class AsyncEngine(ProxyComparable, AsyncConnectable):
 
         """
 
-        return await greenlet_spawn(self.sync_engine.dispose)
+        await greenlet_spawn(self.sync_engine.dispose)
 
 
 class AsyncTransaction(ProxyComparable, StartableContext):
index ce6a0db090c7f7b9cf5cccec9760798c0a34d885..378cbcbf2f8e4c0f93b99fc4b180026e065035de 100644 (file)
@@ -4,6 +4,9 @@
 #
 # This module is part of SQLAlchemy and is released under
 # the MIT License: https://www.opensource.org/licenses/mit-license.php
+
+import asyncio
+
 from . import engine
 from . import result as _result
 from .base import ReversibleProxy
@@ -607,7 +610,7 @@ class AsyncSession(ReversibleProxy):
             :meth:`_asyncio.AsyncSession.close`
 
         """
-        return await greenlet_spawn(self.sync_session.close)
+        await greenlet_spawn(self.sync_session.close)
 
     async def invalidate(self):
         """Close this Session, using connection invalidation.
@@ -625,7 +628,7 @@ class AsyncSession(ReversibleProxy):
         return self
 
     async def __aexit__(self, type_, value, traceback):
-        await self.close()
+        await asyncio.shield(self.close())
 
     def _maker_context_manager(self):
         # no @contextlib.asynccontextmanager until python3.7, gr
@@ -642,8 +645,11 @@ class _AsyncSessionContextManager:
         return self.async_session
 
     async def __aexit__(self, type_, value, traceback):
-        await self.trans.__aexit__(type_, value, traceback)
-        await self.async_session.__aexit__(type_, value, traceback)
+        async def go():
+            await self.trans.__aexit__(type_, value, traceback)
+            await self.async_session.__aexit__(type_, value, traceback)
+
+        await asyncio.shield(go())
 
 
 class AsyncSessionTransaction(ReversibleProxy, StartableContext):