Служба тикает с периодом min(LinkReconciliationSeconds, 30) и на каждом тике безусловно запускает sudo с helper'ом для инспекции маркера. Настройка ограничивает только полный проход, поэтому при 3600 получается около 120 привилегированных запусков в час. Проверка backoff стоит после обращения к маркеру, так что при недоступном firewall вызовы продолжаются. Измерено на локальном прогоне: записи ровно каждые 30 секунд при заданных 3600, при нуле узлов и нуле связей. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
101 lines
6.3 KiB
Markdown
101 lines
6.3 KiB
Markdown
# Согласование Links дёргает привилегированный процесс каждые 30 секунд
|
||
|
||
- **Кому:** `antigravity`
|
||
- **Дата:** 2026-08-20
|
||
- **От кого:** главный агент (`claude`)
|
||
- **Ветка:** `antigravity/reconciliation-poll-interval`
|
||
- **Файл отчёта:** `../done/2026-08-20-reconciliation-poll-interval.md`
|
||
|
||
## Что происходит
|
||
|
||
`LinkReconciliationBackgroundService` тикает с периодом
|
||
`Math.Min(LinkReconciliationSeconds, 30)` (строка 117), то есть **не реже
|
||
раза в 30 секунд при любой настройке**. На каждом тике первым делом
|
||
безусловно вызывается `applier.GetReconciliationRequestAsync(...)`
|
||
(строка 30) — а это запуск внешнего процесса
|
||
`/usr/bin/sudo` + `ochenstarik-smm-policy-apply`
|
||
(`LinkPolicyApplier.RunAsync`, строка 143).
|
||
|
||
Отсюда два следствия.
|
||
|
||
**1. Настройка не ограничивает привилегированные вызовы.**
|
||
`LinkReconciliationSeconds` валидируется в диапазоне 30…3600, и оператор,
|
||
поставивший 3600, вправе ожидать примерно одну активность в час. Фактически
|
||
он получает около **120 запусков sudo в час** — интервал управляет только
|
||
полным проходом `ReconcileAllAsync`, но не инспекцией маркера.
|
||
|
||
**2. Backoff не подавляет эти вызовы.** Проверка `_backoffUntil`
|
||
(строки 35–38) стоит **после** обращения к маркеру. Когда firewall
|
||
недоступен и служба ушла в backoff, она всё равно продолжает запускать
|
||
sudo каждые 30 секунд — ровно в той ситуации, когда предполагалось
|
||
притормозить.
|
||
|
||
Каждая неудачная инспекция пишет предупреждение с полным стеком.
|
||
|
||
## Измерение
|
||
|
||
Control запущен локально с `--Control:LinkReconciliationSeconds=3600`.
|
||
Журнал приложений Windows, провайдер `.NET Runtime`, категория
|
||
`ServerMonitorManager.Control.LinkReconciliationBackgroundService`:
|
||
|
||
```
|
||
17:29:16
|
||
17:29:46
|
||
17:30:16
|
||
17:30:46
|
||
17:31:16
|
||
```
|
||
|
||
Ровно каждые 30 секунд при заданных 3600. Записи идут непрерывно, службы
|
||
в этот момент нечем было заниматься: узлов ноль, связей ноль.
|
||
|
||
## Что нужно сделать
|
||
|
||
Привести поведение в соответствие с настройкой, **не потеряв быструю
|
||
реакцию на маркер** — она и есть смысл 30-секундного опроса, её ломать
|
||
нельзя.
|
||
|
||
Как минимум:
|
||
|
||
1. Не обращаться к маркеру, пока действует `_backoffUntil`. Сейчас backoff
|
||
не защищает ни от чего.
|
||
2. Решить и обосновать в отчёте, каким должен быть контракт
|
||
`LinkReconciliationSeconds`. Либо это интервал полного прохода, и тогда
|
||
частота опроса маркера должна настраиваться отдельным параметром с
|
||
собственной валидацией и описанием. Либо это верхняя граница любой
|
||
активности, и тогда опрос обязан её соблюдать.
|
||
3. Сделать так, чтобы повторяющаяся недоступность helper'а не писала
|
||
полный стек на каждом тике.
|
||
|
||
Выбор между вариантами пункта 2 — за тобой, но он должен быть **выбором с
|
||
обоснованием**, а не молчаливым изменением поведения.
|
||
|
||
## Границы
|
||
|
||
`src/ServerMonitorManager.Control/LinkReconciliationBackgroundService.cs`,
|
||
при необходимости `ControlOptions` и валидация в `Program.cs`, плюс тесты
|
||
`tests/ServerMonitorManager.Control.Tests/LinkReconciliationTests.cs`.
|
||
Не трогать `LinkService.ReconcileAllAsync`, helper в `deploy/**`, консоль
|
||
и Desktop.
|
||
|
||
## Как проверить результат
|
||
|
||
- `dotnet test tests/ServerMonitorManager.Control.Tests/...` — все 158
|
||
существующих тестов зелёные, с выводом. Маркерные тесты трогать только
|
||
если меняется контракт, и тогда объяснить каждое изменение;
|
||
- новый тест на то, что во время backoff обращения к маркеру **не
|
||
происходит**: подменить `ILinkPolicyApplier` и сосчитать вызовы;
|
||
- новый тест на соблюдение настроенного интервала по выбранному контракту;
|
||
- предъявить число вызовов applier за фиксированное время до и после
|
||
правки — как в измерении выше, числами.
|
||
|
||
## Контекст и ограничения
|
||
|
||
Дефект найден на живом прогоне Control на Windows, где helper'а нет вовсе,
|
||
поэтому каждая инспекция падает. На настоящем Hub helper есть и вызовы
|
||
успешны — значит там это не ошибки в журнале, а тихая нагрузка: запуск
|
||
sudo и внешнего процесса дважды в минуту круглосуточно. Оценить, насколько
|
||
это существенно на настоящем Hub, я не могу: живого Hub под рукой нет.
|
||
Если при проверке окажется, что нагрузка пренебрежима и контракт менять не
|
||
нужно, — так и напиши с числами, это допустимый результат. Пункт 1 про
|
||
backoff при этом всё равно остаётся к исправлению.
|