Skip to content

Commit e3dffbe

Browse files
[MAINTENANCE] Dispose of mssql connections in integration tests (#11663)
1 parent 1b24781 commit e3dffbe

File tree

3 files changed

+38
-17
lines changed

3 files changed

+38
-17
lines changed

tests/integration/sql_session_manager.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,20 @@ def get_engine(
7676
logger.info(f"Cache hit for engine: {cache_key}")
7777
return self._engine_cache[cache_key]
7878

79+
def dispose_engine(self, connection_details: ConnectionDetails) -> None:
80+
"""Dispose a specific cached engine and remove it from the cache.
81+
82+
Useful before teardown operations (e.g. DROP SCHEMA) that require all
83+
connections to be released, such as MSSQL which holds schema locks.
84+
"""
85+
if connection_details in self._engine_cache:
86+
engine = self._engine_cache.pop(connection_details)
87+
logger.info(f"Disposing engine for teardown: {connection_details}")
88+
try:
89+
engine.dispose()
90+
except Exception:
91+
logger.exception(f"Error disposing engine '{connection_details}'")
92+
7993
def dispose_all_engines(self):
8094
logger.info("Disposing all cached SQLAlchemy engines.")
8195
for key, engine in self._engine_cache.items():

tests/integration/test_utils/data_source_config/mssql.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
from typing import Mapping, Optional
23

34
import pandas as pd
@@ -9,14 +10,16 @@
910
from great_expectations.datasource.fluent.sql_server_datasource import (
1011
SQLServerAuthConnectionDetails,
1112
)
12-
from tests.integration.sql_session_manager import SessionSQLEngineManager
13+
from tests.integration.sql_session_manager import ConnectionDetails, SessionSQLEngineManager
1314
from tests.integration.test_utils.data_source_config.base import (
1415
BatchTestSetup,
1516
DataSourceTestConfig,
1617
)
1718
from tests.integration.test_utils.data_source_config.sql import SQLBatchTestSetup
1819
from tests.test_utils import get_default_mssql_url
1920

21+
logger = logging.getLogger(__name__)
22+
2023

2124
class MSSQLDatasourceTestConfig(DataSourceTestConfig):
2225
@property
@@ -79,3 +82,23 @@ def make_asset(self) -> TableAsset:
7982
table_name=self.table_name,
8083
schema_name=self.schema,
8184
)
85+
86+
@override
87+
def teardown(self) -> None:
88+
"""Override teardown to dispose cached engines before DROP SCHEMA.
89+
90+
MSSQL holds schema locks on connections. Disposing the session manager's
91+
cached engine releases all pool connections before we run DROP, avoiding
92+
hangs. We use a fresh engine for the drop since the cached one was disposed.
93+
"""
94+
for datasource in self.context.data_sources.all().values():
95+
execution_engine = datasource.execution_engine
96+
if execution_engine:
97+
execution_engine.close()
98+
99+
if self.engine_manager:
100+
self.engine_manager.dispose_engine(
101+
ConnectionDetails(connection_string=self.connection_string)
102+
)
103+
104+
super().teardown()

tests/integration/test_utils/data_source_config/sql.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -232,24 +232,8 @@ def setup(self) -> None:
232232
self._safe_commit(conn)
233233
cleanup()
234234

235-
def _close_execution_engines(self) -> None:
236-
"""Close all execution engines in the data context.
237-
238-
Some dialects (MSSQL, SQLite, BigQuery, Databricks) use persisted
239-
connections that are kept alive for temp-table support. These
240-
connections hold locks that prevent DDL operations like DROP SCHEMA.
241-
Closing them before teardown avoids hangs.
242-
"""
243-
for datasource in self.context.data_sources.all().values():
244-
execution_engine = datasource.execution_engine
245-
if execution_engine:
246-
execution_engine.close()
247-
248235
@override
249236
def teardown(self) -> None:
250-
# Close any execution engine connections that may hold schema locks
251-
self._close_execution_engines()
252-
253237
engine, cleanup = self._get_engine()
254238
with engine.connect() as conn:
255239
for table in self.tables:

0 commit comments

Comments
 (0)