fix(metrics): развязать vidconf_pipeline_sessions с основным пулом БД
_refresh_pipeline_sessions_gauge и metrics_endpoint ходили через Depends(get_session) — основной пул, разделяемый с API-запросами. В инциденте 07.08 это дало 16 падений в api/metrics.py ровно тогда, когда метрики были нужнее всего (пул исчерпан). db_up/db_pool_* уже были развязаны в 0.0.32, эта метрика — нет (мешал тестовый харнесс). Добавлен get_metrics_session (core/db.py) — отдельный движок с NullPool, как у check_db_up, но с полноценной ORM-сессией для репозитория. Тестовый харнесс (app-фикстура) подменяет её на ту же savepoint-сессию, что и get_session, — иначе /metrics не видел бы данные теста.
This commit is contained in:
@@ -65,6 +65,38 @@ async def check_db_up() -> bool:
|
||||
return True
|
||||
|
||||
|
||||
# --- Сессия для метрик, читающих данные (не только «жив/мёртв»), вне основного
|
||||
# пула (сессия 37, доделка session 32/33 — см. докстринг `api/metrics.py`) ----
|
||||
#
|
||||
# `check_db_up` выше обходится голым соединением ("SELECT 1"), но
|
||||
# `vidconf_pipeline_sessions` нужна полноценная ORM-сессия (репозиторий,
|
||||
# группировка по статусу) — `NullPool`, как и у `_probe_engine`: каждый вызов
|
||||
# открывает новое соединение и сразу закрывает его, бюджет основного пула
|
||||
# (`engine.pool`) не расходуется. `async_sessionmaker` — тот же паттерн, что
|
||||
# `async_session_maker` выше, просто на другом движке.
|
||||
_metrics_probe_engine: AsyncEngine = create_async_engine(
|
||||
settings.database_url,
|
||||
poolclass=NullPool,
|
||||
connect_args={"timeout": settings.db_probe_timeout_s},
|
||||
)
|
||||
_metrics_session_maker = async_sessionmaker(_metrics_probe_engine, expire_on_commit=False)
|
||||
|
||||
|
||||
async def get_metrics_session() -> AsyncGenerator[AsyncSession, None]:
|
||||
"""Зависимость FastAPI для метрик, которым нужна БД, но не основной пул.
|
||||
|
||||
В отличие от `get_session()` (основной пул `engine.pool`, конкурирует за
|
||||
те же 10+10×воркеров соединений, что и API-запросы), сессия здесь открыта
|
||||
на `_metrics_probe_engine` — исчерпание основного пула эту метрику не
|
||||
заденет, как и `vidconf_db_up`/`vidconf_db_pool_*`. Тестовый харнесс
|
||||
(`tests/conftest.py`) подменяет и её на savepoint-сессию теста — так же,
|
||||
как `get_session` — иначе тест `vidconf_pipeline_sessions` не видел бы
|
||||
данные, ещё не закоммиченные за пределы savepoint.
|
||||
"""
|
||||
async with _metrics_session_maker() as session:
|
||||
yield session
|
||||
|
||||
|
||||
def db_pool_checked_out() -> int:
|
||||
"""Число соединений основного пула, занятых прямо сейчас — без обращения к БД.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user