From 1c1f60a2e3f199b626edc565ae4a67687e192015 Mon Sep 17 00:00:00 2001 From: Gord Thompson Date: Sun, 14 Jan 2024 09:49:11 -0700 Subject: [PATCH] use ensure_closed() for async close, close() for terminate Fixed issue in asyncio dialects asyncmy and aiomysql, where their ``.close()`` method is apparently not a graceful close. replace with non-standard ``.ensure_closed()`` method that's awaitable and move ``.close()`` to the so-called "terminate" case. Fixes: #10893 Change-Id: I33d871e67854d85f770c46f699e41a6e73b6fbe0 (cherry picked from commit 4201b90210dcf60f9830df299be016dee315753b) --- doc/build/changelog/unreleased_20/10893.rst | 8 ++++++++ lib/sqlalchemy/dialects/mysql/aiomysql.py | 9 ++++++++- lib/sqlalchemy/dialects/mysql/asyncmy.py | 9 ++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 doc/build/changelog/unreleased_20/10893.rst diff --git a/doc/build/changelog/unreleased_20/10893.rst b/doc/build/changelog/unreleased_20/10893.rst new file mode 100644 index 0000000000..63507f38d5 --- /dev/null +++ b/doc/build/changelog/unreleased_20/10893.rst @@ -0,0 +1,8 @@ +.. change:: + :tags: bug, mysql + :tickets: 10893 + + Fixed issue in asyncio dialects asyncmy and aiomysql, where their + ``.close()`` method is apparently not a graceful close. replace with + non-standard ``.ensure_closed()`` method that's awaitable and move + ``.close()`` to the so-called "terminate" case. diff --git a/lib/sqlalchemy/dialects/mysql/aiomysql.py b/lib/sqlalchemy/dialects/mysql/aiomysql.py index 65482a76b2..405fa82c8a 100644 --- a/lib/sqlalchemy/dialects/mysql/aiomysql.py +++ b/lib/sqlalchemy/dialects/mysql/aiomysql.py @@ -202,10 +202,13 @@ class AsyncAdapt_aiomysql_connection(AdaptedConnection): def commit(self): self.await_(self._connection.commit()) - def close(self): + def terminate(self): # it's not awaitable. self._connection.close() + def close(self) -> None: + self.await_(self._connection.ensure_closed()) + class AsyncAdaptFallback_aiomysql_connection(AsyncAdapt_aiomysql_connection): # TODO: base on connectors/asyncio.py @@ -285,6 +288,7 @@ class MySQLDialect_aiomysql(MySQLDialect_pymysql): _sscursor = AsyncAdapt_aiomysql_ss_cursor is_async = True + has_terminate = True @classmethod def import_dbapi(cls): @@ -301,6 +305,9 @@ class MySQLDialect_aiomysql(MySQLDialect_pymysql): else: return pool.AsyncAdaptedQueuePool + def do_terminate(self, dbapi_connection) -> None: + dbapi_connection.terminate() + def create_connect_args(self, url): return super().create_connect_args( url, _translate_args=dict(username="user", database="db") diff --git a/lib/sqlalchemy/dialects/mysql/asyncmy.py b/lib/sqlalchemy/dialects/mysql/asyncmy.py index 9928a879ec..7360044d20 100644 --- a/lib/sqlalchemy/dialects/mysql/asyncmy.py +++ b/lib/sqlalchemy/dialects/mysql/asyncmy.py @@ -221,10 +221,13 @@ class AsyncAdapt_asyncmy_connection(AdaptedConnection): def commit(self): self.await_(self._connection.commit()) - def close(self): + def terminate(self): # it's not awaitable. self._connection.close() + def close(self) -> None: + self.await_(self._connection.ensure_closed()) + class AsyncAdaptFallback_asyncmy_connection(AsyncAdapt_asyncmy_connection): __slots__ = () @@ -290,6 +293,7 @@ class MySQLDialect_asyncmy(MySQLDialect_pymysql): _sscursor = AsyncAdapt_asyncmy_ss_cursor is_async = True + has_terminate = True @classmethod def import_dbapi(cls): @@ -304,6 +308,9 @@ class MySQLDialect_asyncmy(MySQLDialect_pymysql): else: return pool.AsyncAdaptedQueuePool + def do_terminate(self, dbapi_connection) -> None: + dbapi_connection.terminate() + def create_connect_args(self, url): return super().create_connect_args( url, _translate_args=dict(username="user", database="db") -- 2.47.2