Files
admin/.wiki/concepts/sched-runtime-to-file-managed-migration.md

79 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: sched-runtime-to-file-managed-migration
type: concept
status: live
tags: [books, sched, file-managed, durable-config, incident, live-sync]
related: "[[sched-ozon-creds-stub-contract]], [[snolla-smtp-mail-delivery-2026-08]], [[portainer-stack-management-books-vds]]"
updated: 2026-08-23
---
# Sched runtime → file-managed миграция (durable config)
## TL;DR
После инцидента 2026-08-23 (спин `ozonFbsPostingsSyncronization`, ~75 req/сек) оба тенанта books
(slovo + bookva) переведены на **file-managed** расписания sched: декларатив в
`deploy/sched-tasks.json` (git-tracked), демон подхватывает файл live-sync'ом. Runtime-путь
(таски в сторе, `fileManaged:false`) хрупкий — расписания живут в памяти демона и слетают
при pause/перезапуске, таски остаются сиротами без `data`.
**Ключевой факт миграции: live-sync НЕ конвертирует runtime-таски** (sync создаёт только
новые из файла, существующие runtime НЕ перезаписывает). Перевод = явный `DELETE` runtime-
тасок и расписаний через admin API, после чего sync доставляет file-managed версии.
## Почему runtime хрупкий (контекст инцидента)
- Расписания runtime-тасок держатся **в памяти демона** → при `pause`/`restart` слетают.
- Таски остаются сиротами: `fileManaged:false`, `schedule:null`, `data:undefined`.
- `deploy/sched-tasks.json` был **gitignored** (прод-файл на хосте) — конфиг не версионировался,
восстановление = ручные миграции из `agendaJobs`.
- Runtime-таска могла нести **чужой URL runner'а** (cross-tenant leak: `books-task-runner` в
bookva-конфиге) — файл чинит (bookva → `bookva-task-runner`).
## Миграционный рецепт (по тенанту)
1. **Файл** — из git-репо в прод-расположение:
- slovo: `/opt/books/sched/tasks.json` (bind-директория `/opt/books/sched:/app/config:ro`).
- bookva: volume `/var/lib/docker/volumes/bookva-sched-config/_data/tasks.json` (→ `/app/config`).
- Заливка **in-place**: `cp /tmp/new /path/tasks.json` (не mv — сохранить inode/perms).
Бэкап: `cp tasks.json tasks.json.bak-<tag>`.
- Перед заливкой: diff против live — допускаются только целевые изменения (books собирает
файл байт-идентичным live + новые таски).
2. **Live-sync** — демон подхватывает файл ≤60с, рестарт НЕ нужен. Верифицировать через
`GET /api/tasks` (новые таски появляются как `fileManaged:true`).
3. **DELETE runtime** (sync их не убирает — только API, runs-история сохраняется):
- `DELETE /api/tasks/:name` ×N — имена URL-encode (`%20`).
- `DELETE /api/schedules/:id` ×N — **не каскадятся**, удалять отдельно. Все → 204.
4. **Verify**:
- `fileManaged:true` у всех целевых, `disabled:false`, `paused:false`.
- Дублей 0: `[].taskName | group_by(.) | map(select(length>1))` пуст.
- `data` на расписании (не на таске): slovo `{idSeller:2}` / bookva `{idSeller:1}`,
отчёт — `{recipients:[...], idSeller}`.
- Ручной раунд: `POST /api/tasks/:name/run``succeeded {sellersProcessed:N}`.
## Gotchas
| Гоча | Деталь |
|---|---|
| id-паттерн | file-managed schedule `id` = taskName; runtime = UUID |
| ghost-таски | `fileManaged:true` сироты (выпилены из файла) висят `disabled:true` — удалять `DELETE /api/tasks/:name` |
| task-runner config | `/opt/books/task-runner/config/default.json` кэшируется при первом send (lazy init `sendReportsByEmail.js`) → после правки **рестарт обязателен** |
| SMTP | `from` == auth-user обязателен (Yandex: 550 not owned / 525 disabled). Креды `e-16513832@yandex.ru` (app-pass, `pass show snolla-smtp/full-env`). См. [[snolla-smtp-mail-delivery-2026-08]] |
| имена тасок | «ozon fbs postings syncronization» — пробелы, в DELETE URL-encode |
| шаблон vs прод | конвертер из шаблона может давать лишние trigger-only таски — в деплой-файл не включать без причины |
## Текущее состояние (2026-08-23, #991 closed)
- slovo: 25 тасок, file-managed, отчёт `{idSeller:2, recipients:[3]}` (recipients восстановлены,
commit `854e381`).
- bookva: 23 таски, file-managed, `data {idSeller:1}` (commit `6d4f163` bookva-overlay).
- Ghost `system-cleanup-task-runs` удалён на обоих тенантах.
- Доступ: sched admin API — books-sched `172.20.0.20:3031`, bookva-sched `172.20.0.12:3031`,
Bearer `SCHED_ADMIN_KEY` (env контейнера), через SSH books-vds. Роуты — `packages/admin-api/src/admin-api.ts` (репо sched).
## Related
- [[sched-ozon-creds-stub-contract]] — почему мисматч-пары кредов намеренные (тот же инцидент).
- [[snolla-smtp-mail-delivery-2026-08]] — SMTP-уроки (525/554/550), перенос на e-16513832@yandex.ru.
- [[portainer-stack-management-books-vds]] — управление стеками books VDS.