Три async-хендлера competitors / best-layouts / best-layouts-pdf блокируют event loop sync DB-IO (и WeasyPrint write_pdf) #1560

Closed
opened 2026-06-16 17:05:30 +00:00 by bot-backend · 0 comments
Collaborator

Severity: medium · Категория: blocking-sync-io-in-async · Файл: backend/app/api/v1/parcels.py:3176-3195, 3229-3247, 3250-3282

Файл /Users/anton/Птица/gendesign/backend/app/api/v1/parcels.py:3175-3282. Хендлеры объявлены async def, но вызывают чисто синхронные функции без await/threadpool: get_parcel_competitors (3176) → get_competitors(db=...) (3187; competitors.py:518, несколько db.execute — 540/563/630/651); get_parcel_best_layouts (3229) → get_best_layouts(db=...) (3241; best_layouts.py:377, db.execute на 398/418/458/492); get_parcel_best_layouts_pdf (3250) → get_best_layouts(...) (3260) + render_layout_tz_pdf(...) (3261), который делает CPU-bound HTML(string=html).write_pdf() через WeasyPrint (layout_tz_pdf.py:161). Всё исполняется прямо в event loop. Импакт: блокировка loop на время DB-запросов, а у best-layouts/pdf — на сотни мс CPU-рендера WeasyPrint, что особенно опасно. Контекст: соседний get_parcel_competitors_parking (3199) намеренно sync def с комментарием «FastAPI исполняет sync-handler в threadpool, не блокируя event loop» — проект осознаёт паттерн, но эти три остались async. Фикс: перевести три хендлера в sync def (как competitors-parking), либо обернуть тяжёлые вызовы в run_in_threadpool.

Почему баг: Тот же класс, что #1346/#1337: блокирующий sync-IO в async-хендлере замораживает loop. Особенно опасен best-layouts/pdf: WeasyPrint write_pdf() — CPU-heavy, держит loop сотни мс. Соседний по смыслу get_parcel_competitors_parking (строка 3199) намеренно объявлен sync def с комментарием «FastAPI исполняет sync-handler в threadpool, не блокируя event loop» — то есть проект осознаёт паттерн, но эти три хендлера после массфикса остались async и его нарушают.

Как чинить: Перевести все три в sync def (как competitors-parking) — внутри нет await, вызываемые сервисы синхронны; FastAPI уведёт их в threadpool. Альтернатива — обернуть вызовы в anyio.to_thread.run_sync/run_in_threadpool, но проще снять async.


deep-audit backend v2 (после PR #1543) · verify+harden, confidence 0.85 · unit B02

**Severity:** medium · **Категория:** blocking-sync-io-in-async · **Файл:** `backend/app/api/v1/parcels.py:3176-3195, 3229-3247, 3250-3282` Файл /Users/anton/Птица/gendesign/backend/app/api/v1/parcels.py:3175-3282. Хендлеры объявлены `async def`, но вызывают чисто синхронные функции без await/threadpool: `get_parcel_competitors` (3176) → `get_competitors(db=...)` (3187; competitors.py:518, несколько db.execute — 540/563/630/651); `get_parcel_best_layouts` (3229) → `get_best_layouts(db=...)` (3241; best_layouts.py:377, db.execute на 398/418/458/492); `get_parcel_best_layouts_pdf` (3250) → `get_best_layouts(...)` (3260) + `render_layout_tz_pdf(...)` (3261), который делает CPU-bound `HTML(string=html).write_pdf()` через WeasyPrint (layout_tz_pdf.py:161). Всё исполняется прямо в event loop. Импакт: блокировка loop на время DB-запросов, а у best-layouts/pdf — на сотни мс CPU-рендера WeasyPrint, что особенно опасно. Контекст: соседний `get_parcel_competitors_parking` (3199) намеренно sync `def` с комментарием «FastAPI исполняет sync-handler в threadpool, не блокируя event loop» — проект осознаёт паттерн, но эти три остались async. Фикс: перевести три хендлера в sync `def` (как competitors-parking), либо обернуть тяжёлые вызовы в run_in_threadpool. **Почему баг:** Тот же класс, что #1346/#1337: блокирующий sync-IO в async-хендлере замораживает loop. Особенно опасен best-layouts/pdf: WeasyPrint write_pdf() — CPU-heavy, держит loop сотни мс. Соседний по смыслу `get_parcel_competitors_parking` (строка 3199) намеренно объявлен sync `def` с комментарием «FastAPI исполняет sync-handler в threadpool, не блокируя event loop» — то есть проект осознаёт паттерн, но эти три хендлера после массфикса остались async и его нарушают. **Как чинить:** Перевести все три в sync `def` (как competitors-parking) — внутри нет `await`, вызываемые сервисы синхронны; FastAPI уведёт их в threadpool. Альтернатива — обернуть вызовы в `anyio.to_thread.run_sync`/`run_in_threadpool`, но проще снять `async`. --- <sub>deep-audit backend v2 (после PR #1543) · verify+harden, confidence 0.85 · unit B02</sub>
bot-backend added the
week ревью 1
label 2026-06-16 17:05:30 +00:00
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#1560
No description provided.