[P1] Снять блокировку event loop на POST /estimate (asyncio.to_thread) #2207

Closed
opened 2026-07-02 19:17:58 +00:00 by lekss361 · 2 comments
Owner

Эпик: #2200

Находка (Backend, verified high): trade_in.py:145 async def estimateestimator.py:2581 async def estimate_quality выпускает ~28 синхронных psycopg PostGIS-запросов (multi-tier analog fetch ×4 + deals + price_trend) прямо на event loop. grep to_thread|run_in_executor в estimator.py = 0. Прод — один worker uvicorn (docker-compose.prod.yml:64, нет --workers). Паттерн вынесения уже есть в geocoder.py.

Impact: одна медленная оценка (холодный кэш, wide-radius fallback) стопит ВСЕ конкурентные запросы, включая /health (флап healthcheck) и sync-def эндпоинты.

Acceptance:

  • Синхронный DB-путь estimate_quality вынесен в asyncio.to_thread/executor (или endpoint sync-def в threadpool).
  • /health не деградирует под конкурентной нагрузкой (проба на 3-5 параллельных estimate).
  • Не регрессировать транзакционность/сессию БД при выносе.

Scope: tradein-mvp/backend/app/api/v1/trade_in.py, app/services/estimator.py.

Эпик: #2200 **Находка (Backend, verified high):** `trade_in.py:145 async def estimate` → `estimator.py:2581 async def estimate_quality` выпускает ~28 синхронных psycopg PostGIS-запросов (multi-tier analog fetch ×4 + deals + price_trend) прямо на event loop. `grep to_thread|run_in_executor` в estimator.py = 0. Прод — один worker uvicorn (`docker-compose.prod.yml:64`, нет `--workers`). Паттерн вынесения уже есть в `geocoder.py`. **Impact:** одна медленная оценка (холодный кэш, wide-radius fallback) стопит ВСЕ конкурентные запросы, включая `/health` (флап healthcheck) и sync-def эндпоинты. **Acceptance:** - [ ] Синхронный DB-путь `estimate_quality` вынесен в `asyncio.to_thread`/executor (или endpoint sync-def в threadpool). - [ ] `/health` не деградирует под конкурентной нагрузкой (проба на 3-5 параллельных estimate). - [ ] Не регрессировать транзакционность/сессию БД при выносе. Scope: `tradein-mvp/backend/app/api/v1/trade_in.py`, `app/services/estimator.py`.
lekss361 added the
performance
priority/p1
scope/backend
tradein
labels 2026-07-02 19:20:19 +00:00
Author
Owner

Working on this (night shift), ветка fix/tradein-estimate-event-loop. Sync DB-кластеры estimate_quality → asyncio.to_thread (паттерн geocoder.py), Session остаётся последовательным (без конкурентного использования), сигнатуры внутренностей, которые импортирует backtest-harness, не трогаются. + тест на неблокирование event loop.

Working on this (night shift), ветка `fix/tradein-estimate-event-loop`. Sync DB-кластеры estimate_quality → asyncio.to_thread (паттерн geocoder.py), Session остаётся последовательным (без конкурентного использования), сигнатуры внутренностей, которые импортирует backtest-harness, не трогаются. + тест на неблокирование event loop.
Author
Owner

Сделано в PR #2225 (смержен, deploy success).

Post-deploy smoke на проде (изнутри tradein-backend): 3 параллельных POST /estimate (каждый ~7.6-8.7s, все 200) + конкурентный GET /health → 200 за 0.17s (до фикса health ждал бы завершения оценки ~8s). Event loop свободен.

Acceptance:

  • Sync DB-путь estimate_quality вынесен в asyncio.to_thread (15 кластеров, последовательный Session, транзакционные точки не сдвинуты — построчное ревью).
  • /health не деградирует под конкурентной нагрузкой (замер выше).
  • Транзакционность не регрессирована: SAVEPOINT-блок в одном потоке, INSERT+commit сгруппированы атомарно; полный сьют 2960 passed, frozen backtest-гейт зелёный.
Сделано в PR #2225 (смержен, deploy success). **Post-deploy smoke на проде (изнутри tradein-backend):** 3 параллельных POST /estimate (каждый ~7.6-8.7s, все 200) + конкурентный GET /health → **200 за 0.17s** (до фикса health ждал бы завершения оценки ~8s). Event loop свободен. Acceptance: - ✅ Sync DB-путь estimate_quality вынесен в asyncio.to_thread (15 кластеров, последовательный Session, транзакционные точки не сдвинуты — построчное ревью). - ✅ /health не деградирует под конкурентной нагрузкой (замер выше). - ✅ Транзакционность не регрессирована: SAVEPOINT-блок в одном потоке, INSERT+commit сгруппированы атомарно; полный сьют 2960 passed, frozen backtest-гейт зелёный.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#2207
No description provided.