Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 4 additions & 12 deletions alws/utils/fastapi_sqla_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,11 @@ async def setup_all():

async def async_setup():
for key in async_keys:
existing = _async_session_factories.pop(key, None)
if existing is not None:
engine = existing.kw.get('bind')
if engine is not None:
await engine.dispose()
await async_startup(key)
if key not in _async_session_factories:
await async_startup(key)


def sync_setup():
for key in sync_keys:
existing = _session_factories.pop(key, None)
if existing is not None:
engine = existing.kw.get('bind')
if engine is not None:
engine.dispose()
startup(key)
if key not in _session_factories:
startup(key)
28 changes: 28 additions & 0 deletions tests/fixtures/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
from sqlalchemy.orm.session import sessionmaker
from sqlalchemy.pool import NullPool

from fastapi_sqla.async_sqla import _async_session_factories
from fastapi_sqla.sqla import _session_factories

from alws import models
from alws.config import settings
from alws.database import Base
Expand All @@ -15,6 +18,30 @@
from tests.constants import ADMIN_USER_ID, CUSTOM_USER_ID


async def reset_session_factories():
"""Dispose and drop cached fastapi-sqla session factories.

``setup_all()`` is idempotent: it reuses any session factory that is
already registered. That is correct in production, where every service
runs on a single, long-lived event loop. The test suite, however, runs
each module on its own event loop, so a factory (and its asyncpg pool)
cached on a previous module's loop would raise "got Future attached to a
different loop" when reused here. Clearing the caches per module forces
``setup_all()`` to rebuild the engines on the current loop.
"""
for factory in _async_session_factories.values():
engine = factory.kw.get('bind')
if engine is not None:
await engine.dispose()
_async_session_factories.clear()

for factory in _session_factories.values():
engine = factory.kw.get('bind')
if engine is not None:
engine.dispose()
_session_factories.clear()


@pytest.fixture
def async_session_factory():
"""Fastapi-sqla async_session_factory() fixture overload, disabling expire_on_commit."""
Expand Down Expand Up @@ -80,6 +107,7 @@ async def create_tables():
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)

await reset_session_factories()
await setup_all()
async with open_async_session(get_async_db_key()) as async_session:
for user_data in get_user_data():
Expand Down
Loading