49 lines
2.1 KiB
Python
49 lines
2.1 KiB
Python
from __future__ import annotations
|
||
|
||
from sqlalchemy.ext.asyncio import AsyncAttrs, async_sessionmaker, create_async_engine
|
||
from sqlalchemy.orm import DeclarativeBase
|
||
|
||
from app.core.config import settings
|
||
|
||
# Без явных таймаутов зависший/протухший сокет к Postgres (например, тихо
|
||
# оборванное NAT/LB соединение после долгого простоя — ровно то, что могло
|
||
# случиться во время получасовой обработки батча из 230 файлов) блокирует
|
||
# asyncpg НАВСЕГДА: ни ошибки, ни лога, просто вечное ожидание чтения
|
||
# сокета. Это тот же класс проблемы с asyncio.run()-за-asyncio.run() вокруг
|
||
# общего пула соединений, что уже ловили раньше (см. комментарий про
|
||
# engine.dispose() в opencloud_token_store.py) — тут решаем его с другой
|
||
# стороны: даём зависшему соединению упасть с понятной ошибкой вместо
|
||
# бесконечного ожидания.
|
||
_CONNECT_TIMEOUT_SECONDS = 10
|
||
_COMMAND_TIMEOUT_SECONDS = 15
|
||
|
||
connect_args: dict = {}
|
||
if settings.DATABASE_SCHEMA:
|
||
connect_args["server_settings"] = {"search_path": settings.DATABASE_SCHEMA}
|
||
if "sqlite" in settings.DATABASE_URL:
|
||
connect_args["check_same_thread"] = False
|
||
else:
|
||
# timeout/command_timeout — параметры asyncpg.connect(), не SQLAlchemy;
|
||
# aiosqlite их не понимает, поэтому только для не-sqlite URL.
|
||
connect_args["timeout"] = _CONNECT_TIMEOUT_SECONDS
|
||
connect_args["command_timeout"] = _COMMAND_TIMEOUT_SECONDS
|
||
|
||
engine = create_async_engine(
|
||
settings.DATABASE_URL,
|
||
pool_pre_ping=True,
|
||
pool_size=5,
|
||
max_overflow=10,
|
||
pool_timeout=_CONNECT_TIMEOUT_SECONDS,
|
||
connect_args=connect_args,
|
||
)
|
||
|
||
SessionLocal = async_sessionmaker(
|
||
bind=engine,
|
||
autoflush=False,
|
||
expire_on_commit=False,
|
||
)
|
||
|
||
|
||
class Base(AsyncAttrs, DeclarativeBase):
|
||
pass
|