Files
admin/.wiki/concepts/sched-pipelines-local-stack-runbook.md

92 lines
7.3 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-pipelines-local-stack — ранбук локального стенда (sched + воркеры @apilki)
type: concept
tags: [runbook, sched, apilki, worker, deadline, cancel, local-stand]
related: [concepts/runbooks-index.md]
updated: 2026-08-26
---
# sched-pipelines-local-stack — локальный стенд пайплайнов клиентов
> **⚙️ СЛУЖЕБНЫЙ РАНБУК — только для администратора проекта `.admin`.**
> Применять/выполнять шаги может только **`.admin`** (оператор проекта admin). Другим проектам/агентам — читать по запросу, не выполнять.
> Из проекта не выносить: не копировать в другие вики, не пересказывать, не публиковать.
> Нужен деплой или прод-операция по этому ранбуку — **поставить задачу админу (`.admin`) и написать письмо**. Админ выполняет, остальные верифицируют.
Локальный стенд: sched daemon + HTTP-воркеры (yandex-market-partner-api-client, ozon-seller-api-client)
+ CDP-browser + локальный ntfy + alert-bridge. Цель — обкатка пайплайнов клиентов `@apilki`
против моков (verdaccio + Gitea) перед миграцией на VDS.
## Локация и команды
```bash
cd ~/projects/.admin/host-stacks/local/sched-pipelines
node render-tasks.cjs # рендер tasks.generated.json из tasks.json + .env
docker compose up -d --build # сборка + запуск
docker compose up -d --force-recreate schedd # применить НОВЫЙ tasks.json (см. gotcha 2)
docker compose logs -f schedd
```
- Admin API sched: `127.0.0.1:18080`, ключ `SCHED_ADMIN_KEY` (pass `sched-pipelines/local/*`).
- Триггер рана: `POST /api/tasks/<name>/run` (Bearer admin key).
- Секреты: `.env` (gitignored) ← `pass sched-pipelines/local/*`.
## Компоненты
| Сервис | Хост-порт | Образ |
|---|---|---|
| schedd | 127.0.0.1:18080 | `sched-pipelines/schedd:local` (daemon с verdaccio) |
| ym-client-builder | 127.0.0.1:18090 | `sched-pipelines/ym-client-builder:local` (из репо yandex) |
| ozon-seller-builder | 127.0.0.1:18091 | `sched-pipelines/ozon-seller-builder:local` (из репо ozon) |
| browser-cdp, ntfy, alert-bridge, unisender-mock | — | локальные |
Воркеры собираются из dev-репо: `../../../../yandex-market-partner-api-client` (Dockerfile),
`../../../../ozon-seller-api-client` (service/Dockerfile). **Свежие фичи на стенд = pull репо + `docker compose build ym-client-builder ozon-seller-builder` + up -d.**
## Таймаут-сценарий (deadline-stop, ратифицирован 2026-08-26)
Инцидент: sched при poll-timeout помечал ран failed, но НЕ слал воркеру cancel — воркер доделывал
пайплайн с реальным publish. Вердикт расходился с реальностью. Закрыт двумя слоями:
1. **Воркер** (yandex #1276, ozon #1278, паттерн C): `data.timeoutMs` (relative) / `data.deadlineMs`
(absolute epoch) / env `WORKER_TIMEOUT_MS` → локальный таймер ставит флаг, пайплайн стопается
на границе стадий ДО мутаций (publish/githubDistro). Вердикт: `failed`, `error: deadline exceeded`,
`result {verdict: 'timeout', timedOut: true, failedStage}`. Операторский cancel остаётся `cancelled`.
2. **sched** (#1277, core 0.53.0): при task-ceiling (`task.timeoutMs`) сам шлёт `POST /cancel` воркеру
перед записью вердикта failed (`run timeout after Nms`).
Проверено на стенде 2026-08-26:
- воркер: `[deadline] fired ... stop before mutations``[cancel] stop before stage fix` → failed, verdaccio чист;
- sched: `[cancel] received/flag set runId=<id>` в логах воркера → failed, verdaccio чист.
## Gotchas (2026-08-26)
1. **`task.timeoutMs``config.timeoutMs`.** `task.timeoutMs` — task-level ceiling (run-deadline,
при срабатывании sched шлёт cancel + failed «run timeout after Nms»). `config.timeoutMs`
транспортный таймаут ОДНОГО poll-запроса (дефолт 30s). Если транспортный < ceiling — ран упадёт
по транспортному (в ветке poll-ошибки cancel НЕ шлётся!) раньше, чем сработает ceiling.
Настройка: `task.timeoutMs: 120000` (ceiling) + `config.timeoutMs: 300000` (транспортный > ceiling).
2. **`applyTask` при upsert существующей таски НЕ обновляет `data` и `config.timeoutMs`** (переносит
только task.timeoutMs). Изменение `data` в tasks.json требует `docker compose up -d --force-recreate schedd`
(просто `up -d` не пересоздаёт контейнер, таска в БД остаётся старой). Диагностика: `GET /api/tasks`
— сверить, что новое поле реально в API.
3. **Состояние воркеров** — bind-mount `data-ym/state.json`, `data-ozon/state.json` (не в слое образа).
Перед форс-тестом полного пайплайна — сбросить state (`{"verdictHistory": []}`) с бэкапом.
После теста — восстановить из бэкапа, иначе следующий ран пойдёт по-старому.
4. **Логи ранов двух воркеров перемешиваются** в одном stdout — различать по `runId` в строках
`[deadline]/[cancel]` и по таймштампам (`docker logs -t`).
5. **schedd молчит в stdout** — диагностика ранов через admin API (`/api/runs`, error-поле),
события cancel — только в логах ВОРКЕРА (`[cancel] received/flag set`).
6. **`classify: таблица рецептов не прочитана (/app/recipes.json)`** — рецепты не смонтированы в
образ ym-client-builder, все изменения классифицируются как auto. Некритично для мок-стенда,
при миграции на VDS смонтировать.
7. **Локальный дедлайн теста**: deadlineMs/таймер проверяются на границе стадий — если стадия долгая
(generate ~15 мин), стоп случится ПОСЛЕ неё (лог `[cancel] stop before stage <next>`), это ок.
## Связи
- `runbooks-index.md` — индекс ранбуков.
- Таска-источник: `.tasks/done/2026-08-20-00746-sched-pipelines-local-stack.md` (мок-кампания 2026-08-20/21).
- `publish-model` (yandex-market-partner-api-client) — модель пайплайна клиентов.
- `worker-deadline-contract.md` (yandex wiki:3254) — конвенция deadline-stop паттерна C.