2 changed files with 36 additions and 0 deletions
|
|
@ -35,6 +35,22 @@ engine = create_engine(
|
|||
# которые пул закрывает сам. Потолок процесса: 5 + 15 = 20; воркер один
|
||||
# (docker-compose.prod.yml, uvicorn без --workers), Postgres max_connections=100.
|
||||
max_overflow=15,
|
||||
# #3408 п.2. Дефолтные 30 с ожидания коннекта длиннее ЛЮБОГО бюджета внешнего
|
||||
# источника в эстиматоре: 8 с (Yandex / Cian / house_meta), 12 с (geocode),
|
||||
# 20 с (Avito IMV — `estimate_avito_imv_timeout_s`, config.py:852). Сам чекаут
|
||||
# прервать `asyncio.wait_for` не может: он занимает поток `asyncio.to_thread`
|
||||
# целиком, а пул потоков конечен (min(32, cpu+4)) — исчерпанный пул коннектов
|
||||
# так превращается в исчерпанный пул потоков. 5 с короче самого КОРОТКОГО
|
||||
# бюджета: занятый пул деградирует ОДИН источник, а не весь запрос.
|
||||
#
|
||||
# Отдельный коммит в конце ветки намеренно (ревью PR #3444): это единственная
|
||||
# правка, которая меняет режим отказа с «медленно» на «быстро с ошибкой», и
|
||||
# едет она во ВСЕ сервисы образа — backend, scraper, tgbot
|
||||
# (tradein-mvp/docker-compose.prod.yml). За 29 ч логов исчерпания пула не было
|
||||
# ни разу, то есть новое значение на проде пока не на чем проверить.
|
||||
# ТРИГГЕР ОТКАТА на 30 с: любое `QueuePool limit ... timed out` в логах
|
||||
# бэкенда ЛИБО рост failed+zombie в `scrape_runs` после деплоя.
|
||||
pool_timeout=5,
|
||||
)
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine, expire_on_commit=False)
|
||||
|
||||
|
|
|
|||
|
|
@ -49,3 +49,23 @@ def test_pool_ceiling_covers_declared_concurrency() -> None:
|
|||
f"({_ESTIMATE_CONCURRENCY} оценок + {_SUGGEST_CONCURRENCY} подсказок + "
|
||||
f"{_MAX_DEFERRED_REFRESH_TASKS} фоновых догрузок) — штатная работа исчерпает пул"
|
||||
)
|
||||
|
||||
|
||||
def test_pool_checkout_wait_shorter_than_source_budget() -> None:
|
||||
"""Ожидание коннекта короче бюджета внешнего источника.
|
||||
|
||||
Иначе занятый пул съедает весь бюджет запроса (и поток `asyncio.to_thread`,
|
||||
которых тоже конечное число) вместо того, чтобы деградировать один источник.
|
||||
Сравниваем с самым КОРОТКИМ бюджетом (8 с Yandex/Cian): geocode 12 с и IMV
|
||||
20 с длиннее, их этот же потолок покрывает с запасом.
|
||||
"""
|
||||
from app.core.config import settings
|
||||
|
||||
budget = min(
|
||||
settings.estimate_yandex_valuation_timeout_s,
|
||||
settings.estimate_cian_valuation_timeout_s,
|
||||
)
|
||||
|
||||
assert engine.pool.timeout() < budget, (
|
||||
f"pool_timeout {engine.pool.timeout()}с >= бюджета источника {budget}с"
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue