Skip to content
This repository was archived by the owner on Aug 19, 2025. It is now read-only.

Commit 57197d7

Browse files
authored
Merge pull request #158 from rafalp/fix-157
Delay global_connection and global_transaction initialization to latest possible moment
2 parents f738907 + af6c1ef commit 57197d7

File tree

2 files changed

+42
-8
lines changed

2 files changed

+42
-8
lines changed

databases/core.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,6 @@ def __init__(
7373
self._global_connection = None # type: typing.Optional[Connection]
7474
self._global_transaction = None # type: typing.Optional[Transaction]
7575

76-
if self._force_rollback:
77-
self._global_connection = Connection(self._backend)
78-
self._global_transaction = self._global_connection.transaction(
79-
force_rollback=True
80-
)
81-
8276
async def connect(self) -> None:
8377
"""
8478
Establish the connection pool.
@@ -92,7 +86,14 @@ async def connect(self) -> None:
9286
self.is_connected = True
9387

9488
if self._force_rollback:
95-
assert self._global_transaction is not None
89+
assert self._global_connection is None
90+
assert self._global_transaction is None
91+
92+
self._global_connection = Connection(self._backend)
93+
self._global_transaction = self._global_connection.transaction(
94+
force_rollback=True
95+
)
96+
9697
await self._global_transaction.__aenter__()
9798

9899
async def disconnect(self) -> None:
@@ -102,9 +103,14 @@ async def disconnect(self) -> None:
102103
assert self.is_connected, "Already disconnected."
103104

104105
if self._force_rollback:
106+
assert self._global_connection is not None
105107
assert self._global_transaction is not None
108+
106109
await self._global_transaction.__aexit__()
107110

111+
self._global_transaction = None
112+
self._global_connection = None
113+
108114
await self._backend.disconnect()
109115
logger.info(
110116
"Disconnected from database %s",

tests/test_databases.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def async_adapter(wrapped_func):
100100

101101
@functools.wraps(wrapped_func)
102102
def run_sync(*args, **kwargs):
103-
loop = asyncio.get_event_loop()
103+
loop = asyncio.new_event_loop()
104104
task = wrapped_func(*args, **kwargs)
105105
return loop.run_until_complete(task)
106106

@@ -752,6 +752,34 @@ async def db_lookup():
752752
await asyncio.gather(db_lookup(), db_lookup())
753753

754754

755+
@pytest.mark.parametrize("database_url", DATABASE_URLS)
756+
def test_global_connection_is_initialized_lazily(database_url):
757+
"""
758+
Ensure that global connection is initialized at latest possible time
759+
so it's _query_lock will belong to same event loop that async_adapter has
760+
initialized.
761+
762+
See https://github.com/encode/databases/issues/157 for more context.
763+
"""
764+
765+
database_url = DatabaseURL(database_url)
766+
if database_url.dialect != "postgresql":
767+
pytest.skip("Test requires `pg_sleep()`")
768+
769+
database = Database(database_url, force_rollback=True)
770+
771+
@async_adapter
772+
async def run_database_queries():
773+
async with database:
774+
775+
async def db_lookup():
776+
await database.fetch_one("SELECT pg_sleep(1)")
777+
778+
await asyncio.gather(db_lookup(), db_lookup())
779+
780+
run_database_queries()
781+
782+
755783
@pytest.mark.parametrize("database_url", DATABASE_URLS)
756784
@async_adapter
757785
async def test_iterate_outside_transaction_with_values(database_url):

0 commit comments

Comments
 (0)