--- work_item: ORCH-100 stage: architecture author_agent: architect status: proposed created_at: 2026-06-10 model_used: claude-opus-4-8 --- # 07 — Инфра-требования: ORCH-100 — FND/F1b: sidecar-watchdog Work Item: **ORCH-100** · Repo: **orchestrator** · Стадия: architecture > When-applicable: топология **меняется** (новый рантайм-контейнер). Разовое инфра-действие выполняет > человек (Слава/Стрим) на хосте mva154; дальше код `watchdog/` катится через конвейер (self-hosting). ## I-1. Топология / окружения Новый сервис `orchestrator-watchdog` в `docker-compose.yml` — **отдельный контейнер** рядом с `orchestrator` (8500) и `orchestrator-staging` (8501, profile staging). - **Образ:** `build: ./watchdog` (`watchdog/Dockerfile`, `python:3.12-slim`, stdlib-only). - **Сеть:** `network_mode: host` — достаёт `/metrics` орка как `http://127.0.0.1:8500/metrics` и хост-интерфейсы (ADR-001 D2). - **Тома (все read-only к наблюдаемому, NFR-4):** - `/var/run/docker.sock:/var/run/docker.sock:ro` — статусы контейнеров (GET-only). - `/home/slin/repos:/repos:ro` и `./data:/app/data:ro` (или эквивалент) — дисковые метрики хоста через `shutil.disk_usage` (те же пути, что у `disk_watchdog`). - **Лимиты:** `mem_limit: 128m` + `mem_reservation: 32m` (тонкость измерима/принудительна, NFR-2); `restart: unless-stopped` (самовосстановление, FR-1). - **Kill-switch:** `WATCHDOG_ENABLED` (env). `false` → демон инертен (idle-loop, не exit — чтобы `restart` не крутил петлю), нулевой эффект на орк. - **Контейнеры под наблюдением (BR-4):** минимум `orchestrator`; список `WATCHDOG_CONTAINERS` (CSV). - **Образец сервиса (ориентир для developer; точные пути сверить с актуальным `docker-compose.yml`):** ```yaml orchestrator-watchdog: build: ./watchdog container_name: orchestrator-watchdog restart: unless-stopped network_mode: host mem_limit: 128m mem_reservation: 32m volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - /home/slin/repos:/repos:ro - ./data:/app/data:ro env_file: .env.watchdog # ЛИБО общий .env с префиксом WATCHDOG_ (деталь — developer/оператор) group_add: ["999"] # docker-группа для чтения docker.sock (как у орка) ``` ## I-2. Переменные окружения / секреты Канон (без секретов) — в `.env.example` (TRZ §2). Префикс `WATCHDOG_` (изоляция от `ORCH_`): - **Секреты (только на хосте, в гит НЕ коммитятся):** `WATCHDOG_TG_BOT_TOKEN`, `WATCHDOG_TG_CHAT_ID` — **собственные** bot/chat sidecar, независимые от Telegram орка (BR-8). Отсутствие → sidecar логирует и не шлёт (fail-safe), но не падает. - **Управление:** `WATCHDOG_ENABLED` (kill-switch), `WATCHDOG_INTERVAL_S` (дефолт 60), `WATCHDOG_ORCH_METRICS_URL` (дефолт `http://127.0.0.1:8500/metrics`). - **Пороги/таймауты (дефолты — ADR-001 D5):** `WATCHDOG_ORCH_DOWN_TICKS=3`, `WATCHDOG_MEM_PCT=90`, `WATCHDOG_DISK_CRIT_ENABLED=false`, `WATCHDOG_DISK_CRIT_PCT=97`, `WATCHDOG_AGENT_HUNG_MIN=20`, `WATCHDOG_AGENT_CPU_FLOOR=0.01`, `WATCHDOG_STAGE_STUCK_MIN=120`, `WATCHDOG_QUEUE_DEPTH=20`, `WATCHDOG_COOLDOWN_S` (анти-спам realert), `WATCHDOG_HTTP_TIMEOUT_S`. - **Цели:** `WATCHDOG_CONTAINERS` (CSV, дефолт `orchestrator`), `WATCHDOG_DEP_PLANE_URL`/ `WATCHDOG_DEP_GITEA_URL`/`WATCHDOG_DEP_ANTHROPIC_URL` (health/ping). > Анти-дубль диск-алерта (ADR-001 D6): штатный 85%-алерт остаётся за внутренним `disk_watchdog` > (ORCH-063). `WATCHDOG_DISK_CRIT_ENABLED` по умолчанию `false` — sidecar НЕ дублирует диск, пока > оператор осознанно не включит независимый критический потолок. ## I-3. Деплой / рестарт - **Разовое действие человеком на хосте (Слава/Стрим):** 1. Создать **отдельного** Telegram-бота watchdog + получить chat-id; положить `WATCHDOG_TG_*` в `.env.watchdog` (или `.env`) на хосте. 2. Заполнить пороги/интервалы (дефолты годятся), включить `WATCHDOG_ENABLED=true`. 3. Добавить сервис в `docker-compose.yml` (приходит с PR) и поднять **только его:** `docker compose up -d --build orchestrator-watchdog`. - **Self-hosting инвариант (критично):** поднятие/пересборка `orchestrator-watchdog` **НЕ** трогает прод-контейнер `orchestrator` (отдельный сервис) — конвейер всех проектов не прерывается. **НЕ** выполнять `docker compose up -d` без явного имени сервиса, если это спровоцирует рекреейт орка. - **Прод-выкат кода watchdog** — через штатный self-hosting-конвейер и **обязательный staging-гейт (8501)** перед прод-деплоем; деплой sidecar не рестартит прод-контейнер орка. - **Проверка после старта (NFR-7):** `docker logs orchestrator-watchdog` показывает старт + тики; тестовый алерт приходит в канал watchdog; остановка орка (на staging) → приходит `orch_down`. ## I-4. CI/CD - Без изменений `.gitea/workflows/` по существу: новые тесты sidecar (`watchdog/tests/` или `tests/watchdog/`) подхватываются существующим `pytest tests/`/прогоном (изолированы, чистые функции — без контейнера/таймера). Если выбран отдельный путь `watchdog/tests/`, developer обеспечивает его включение в существующий тест-ран (без нового workflow-файла). - Docker-сборка нового образа — стандартным `docker compose build` (отдельный `watchdog/Dockerfile`), без правок пайплайна CI.