+34
-10
backend/src/backend/utilities/database.py
+34
-10
backend/src/backend/utilities/database.py
···
6
6
from contextlib import asynccontextmanager
7
7
from typing import Any
8
8
9
-
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, create_async_engine
10
-
from sqlalchemy.orm import sessionmaker
9
+
from sqlalchemy.ext.asyncio import (
10
+
AsyncEngine,
11
+
AsyncSession,
12
+
async_sessionmaker,
13
+
create_async_engine,
14
+
)
11
15
12
16
from backend.config import settings
13
17
14
-
# per-event-loop engine cache
18
+
# per-event-loop engine and sessionmaker cache.
19
+
# sessionmaker is cached alongside engine since it's bound to a specific engine.
15
20
ENGINES: dict[tuple[Any, ...], AsyncEngine] = {}
21
+
SESSION_MAKERS: dict[tuple[Any, ...], async_sessionmaker[AsyncSession]] = {}
16
22
17
23
18
24
def get_engine() -> AsyncEngine:
···
73
79
return ENGINES[cache_key]
74
80
75
81
82
+
def get_session_maker() -> async_sessionmaker[AsyncSession]:
83
+
"""retrieve a cached async sessionmaker.
84
+
85
+
the sessionmaker is cached per event loop alongside the engine.
86
+
this avoids recreating the sessionmaker on every db_session() call.
87
+
88
+
returns:
89
+
async_sessionmaker bound to the current event loop's engine
90
+
"""
91
+
loop = get_running_loop()
92
+
cache_key = (loop, settings.database.url)
93
+
94
+
if cache_key not in SESSION_MAKERS:
95
+
engine = get_engine()
96
+
SESSION_MAKERS[cache_key] = async_sessionmaker(
97
+
bind=engine,
98
+
class_=AsyncSession,
99
+
expire_on_commit=False,
100
+
)
101
+
102
+
return SESSION_MAKERS[cache_key]
103
+
104
+
76
105
@asynccontextmanager
77
106
async def db_session() -> AsyncGenerator[AsyncSession, None]:
78
107
"""get async database session."""
79
-
engine = get_engine()
80
-
async_session_maker = sessionmaker( # type: ignore
81
-
bind=engine, # type: ignore
82
-
class_=AsyncSession,
83
-
expire_on_commit=False,
84
-
)
85
-
async with async_session_maker() as session:
108
+
session_maker = get_session_maker()
109
+
async with session_maker() as session:
86
110
yield session
87
111
88
112