Пул создавался с дефолтом SQLAlchemy (5 + 10) и под нагрузкой выгребался за секунды. Теперь параметры заданы явно и вынесены в настройки: DB_POOL_SIZE=10, DB_MAX_OVERFLOW=10, DB_POOL_TIMEOUT=10. Таймаут снижен с дефолтных 30 секунд намеренно — пусть запрос падает быстро и показывает проблему, а не висит полминуты. Backend запускался одним процессом uvicorn: любой блокирующий вызов останавливал и параллельные запросы, и WS-чат всех участников. Добавлен UVICORN_WORKERS с дефолтом 2 — не по числу ядер, потому что на четырёхъядерном сервере ядра делятся с LiveKit, а медиа важнее API. Бюджет соединений считается на весь инстанс: каждый воркер держит свой пул, поэтому UVICORN_WORKERS × (DB_POOL_SIZE + DB_MAX_OVERFLOW) должно оставаться заметно ниже max_connections у Postgres. Многопроцессность безопасна: бутстрап настроек в lifespan идемпотентен (INSERT ... ON CONFLICT DO NOTHING), а WS-чат разносит сообщения через Redis pub/sub и состояния в памяти процесса не держит.
34 lines
1.1 KiB
Python
34 lines
1.1 KiB
Python
"""Настройка асинхронного движка SQLAlchemy и сеанса."""
|
|
|
|
from collections.abc import AsyncGenerator
|
|
|
|
from sqlalchemy.ext.asyncio import (
|
|
AsyncEngine,
|
|
AsyncSession,
|
|
async_sessionmaker,
|
|
create_async_engine,
|
|
)
|
|
|
|
from core.config import get_settings
|
|
|
|
settings = get_settings()
|
|
|
|
engine: AsyncEngine = create_async_engine(
|
|
settings.database_url,
|
|
pool_pre_ping=True,
|
|
# Параметры пула — в настройках (`core/config.py`, там же расчёт бюджета
|
|
# соединений на инстанс). Дефолт SQLAlchemy 5 + 10 под нагрузкой
|
|
# выгребался за секунды.
|
|
pool_size=settings.db_pool_size,
|
|
max_overflow=settings.db_max_overflow,
|
|
pool_timeout=settings.db_pool_timeout,
|
|
)
|
|
|
|
async_session_maker = async_sessionmaker(engine, expire_on_commit=False)
|
|
|
|
|
|
async def get_session() -> AsyncGenerator[AsyncSession, None]:
|
|
"""Зависимость FastAPI, возвращающая `AsyncSession`."""
|
|
async with async_session_maker() as session:
|
|
yield session
|