fix(db): индексировать историю для очистки планировщика
Docker images / prepare-release (push) Successful in 14s
Docker images / backend-test (push) Failing after 2m49s
Docker images / backend-image (push) Skipped
Docker images / frontend-image (push) Successful in 2m39s
Docker images / notify-webhook (push) Skipped
Docker images / updater-image (push) Successful in 42s
Docker images / publish-release (push) Skipped

This commit is contained in:
Denozordec committed 2026-10-15 22:04:38 +07:00
1 parent fda7f353ad
commit b2cf71fcc7
7 files changed
+136 -2

No files matched your search

+50
View File
@@ -0,0 +1,50 @@
# Индекс истории планировщика — 2026-10-15
Диагностика production: scheduler_runs около1.06M строк/853МБ, retention DELETE после каждого задания, индекса finished_at нет. Наблюдалось ожидание IO/AioIoCompletion; EXPLAIN эквивалентного SELECT показал полный скан. Это подтверждает лишнюю нагрузку БД, но не доказывает причину каждого тайм-аута RouterOS.
Миграция0013 создаёт индекс для новых установок и последующего старта backend. Для работающей установки ниже приведён отдельный online-вариант. **На production выполнен 2026-10-15, запуск в14:55:45 UTC, после разрешения владельца только на индекс и проверку нагрузки.** Создание индекса изменяет БД и временно добавляет нагрузку на CPU/диск.
Подключение psql к текущему mmapp-postgres, без вывода пароля:
```bash
docker exec -it mmapp-postgres sh -c 'exec psql -X -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$POSTGRES_DB"'
```
Сначала проверить, что имя не занято другим или невалидным индексом:
```sql
SELECT indexrelid::regclass, indisvalid, indisready, pg_get_indexdef(indexrelid)
FROM pg_index WHERE indexrelid = to_regclass('public.idx_scheduler_runs_finished_at');
```
Если индекс отсутствует, выполнить **вне BEGIN/транзакции**:
```sql
SET lock_timeout = '5s';
SET statement_timeout = '10min';
CREATE INDEX CONCURRENTLY idx_scheduler_runs_finished_at
ON public.scheduler_runs (finished_at);
RESET statement_timeout;
RESET lock_timeout;
```
При прерывании concurrent build не повторять вслепую с IF NOT EXISTS: сначала проверить indisvalid/indisready. Если остался невалидный индекс, отдельно согласовать его удаление и повторное построение.
После успеха повторить проверку определения и валидности индекса, снять EXPLAIN условия retention и сравнить CPU/IO в нескольких окнах. При очень большой доле устаревших строк PostgreSQL может обоснованно выбрать Seq Scan; не отключать его принудительно. Срок хранения30 дней и код удаления не меняются. Индекс не удаляет записи и не требует перезапуска контейнеров.
Удаление индекса, перезапуски и изменение ресурсов не входят в эту процедуру. Исправление карты — отдельный frontend-патч и само этим SQL не разворачивается.
## Результат применения (2026-10-15)
CREATE INDEX CONCURRENTLY завершён успешно; indisvalid/indisready=true. Повторная проверка в15:01:30 UTC:23МБ,697 использований индекса. EXPLAIN эквивалентного SELECT retention: Bitmap Heap Scan → Bitmap Index Scan idx_scheduler_runs_finished_at вместо Parallel Seq Scan. EXPLAIN ANALYZE DELETE не запускался.
| Измерение | До индекса | После,14:56 UTC | После,15:00 UTC |
| --- | --- | --- | --- |
| CPU контейнера PostgreSQL, docker stats | 66,51% | 0,16% | 0,13% |
| CPU idle сервера, секундные vmstat | 0% | 74–94% | 94–97% |
| CPU iowait сервера, секундные vmstat | 29–34% | 0–5% | 0–1% |
| IO pressure some avg10 | 63,67% | 1,70% | 0,48% |
Первая строка vmstat (среднее с загрузки ОС) исключена из сравнения. Замеры показывают устойчивое улучшение в пределах нескольких минут обычной работы, а не нагрузочную приёмку или гарантию отсутствия всех тайм-аутов. PostgreSQL/контейнеры не перезапускались; ручное удаление данных, изменение retention и параметров приложения не выполнялись. Действующий штатный retention продолжал работать.
Автоматическая проверка фактического SQL миграции выполнена на отдельном тестовом Debian в контейнере mmapp-test-backend:20тыс. временных строк, повторный запуск, валидность индекса, смена плана и сохранение результата выборки. Тест не запускает bootstrap и не изменяет public-таблицы. Backend build и scoped ESLint прошли. [Структурированный протокол](../docs/ux-ui/acceptance/prod266-retention.json).