Остаток п. 9 ревью: синхронная БД вне event loop, повторное ревью

Повторное ревью кодовой базы: docs/reviews/2026-09-28-1243-codebase-review.md
(статус 12 замечаний, новые замечания 13–16).

Остаток п. 9 (docs/changes/022):
- 14 async-функций API, UI и сервисов больше не обращаются к SQLite
  напрямую — через asyncio.to_thread; jobs.start_jobs стал async (БД в
  потоке, create_task в event loop); ops._conn для подключения к устройству;
- тест-линтер по AST: в async def нет прямых вызовов функций с
  session_scope — защита от регресса.

Тесты: 29 из 29. Стенд: задачи и актор событий в порядке, параллельные
запросы не ждут медленного устройства, боевые данные не изменены.
Ручная проверка UI пользователем на момент коммита не подтверждена.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ayurishchevandClaude Opus 5.5 committed 2026-09-28 17:12:44 +03:00
1 parent c4079724c5
commit 0bda0038d0
10 files changed
+320 -39

No files matched your search

@@ -0,0 +1,25 @@
# Итоги: 022 — остаток п. 9: синхронная БД в async-коде
Источник — ревью `docs/reviews/2026-09-28-1243-codebase-review.md`, п. 9 (частично закрыт в 019).
## Сделано
- Разведка по AST нашла 14 async-функций с прямыми синхронными обращениями к SQLite (в ревью были названы 2) — все переведены на `asyncio.to_thread`;
исключение — `lifespan` (выполняется до приёма запросов).
- `jobs.start_jobs` — `async`: БД и события `job.created` — синхронная `_create_jobs` в потоке, `create_task` — в event loop; все вызовы с `await`.
- `ops._conn` — чтение устройства и расшифровка пароля в потоке во всех операциях (опрос, бэкап, канал, обновления ROS/FW); `refresh_many` — список устройств в потоке.
- Группировка нескольких запросов одного ответа в один `to_thread`: `backups.search`, `backups_page`, `device_create`.
- API (`refresh_device`, `put_channel`, `refresh_all`, `list_backups`, `batch`, `batch_channel`, запуск задач) и UI (`refresh`, `batch`, `device_action`,
`device_create`, `backups_page`) — без синхронной БД в event loop.
- Тест-линтер `test_no_sync_db_calls_in_async_functions`: AST-обход `app/` — в `async def` нет прямых вызовов функций с `session_scope` (напрямую или через одну ступень);
ссылки в `asyncio.to_thread(fn, …)` и вложенные `def` не считаются; сообщение называет файл, функцию и вызов.
## Проверено
- `pytest`: 29 из 29.
- Мутация: прямой `get_device` в `refresh_device` → линтер падает с точным местом; файл восстановлен.
- Стенд (8001): бэкап и групповая смена канала для временного устройства → 202, задачи `failed` (`ConnectTimeout`, ожидаемо), актор всех событий задач — `api`
(контекст в потоке сохраняется); во время 4-секундного `refresh` параллельные `GET /devices` — 0,011 с, `GET /backups` — 0,125 с.
- Боевые данные: группы 3/3, устройства 14/14; добавлены только данные проверки (2 задачи, запись неудачного бэкапа, события); временное устройство удалено.
## Оговорки
- Линтер видит одну ступень транзитивности: функция, обращающаяся к БД через две и более промежуточных, не будет обнаружена.
- Ручная проверка UI пользователем на момент коммита не подтверждена.