События и синхронизация
Между копиями агент не опрашивает сервер по таймеру, а держит открытым один запрос и ждёт на нём событие. Соединение может висеть до часа — это штатный режим канала, а не зависший запрос.
#Зачем long-poll
Агенту нужно быстро узнавать о четырёх вещах: появилось задание на копию, запрошено восстановление, отозван токен, изменилась политика хранения. Опрос раз в минуту даёт минуту задержки и тысячи пустых запросов в сутки на каждого агента. Постоянное соединение с ожиданием на сервере снимает и то, и другое.
Мы сознательно не стали брать сюда веб-сокеты: канал односторонний и редкий, а держать его через корпоративные шлюзы и межсетевые экраны обычным HTTPS-запросом гораздо спокойнее. Обычный GET, который долго не отвечает, проходит везде.
#Канал v3
Агент отправляет запрос и ждёт. Сервер отвечает сразу, если события уже накопились, иначе удерживает соединение до истечения wait и возвращает пустой список — это не ошибка, а нормальное завершение цикла.
curl -N "https://vault.goida.fun/api/v3/sync?cursor=ev_918447&wait=1800" \
-H "Authorization: Bearer vlt_ag_7Q2m4Xd9pKcRt6Yb" \
-H "X-Vault-Agent: db-01"
{
"cursor": "ev_918452",
"events": [
{
"id": "ev_918449",
"type": "job.scheduled",
"at": "2026-07-30T21:00:03Z",
"job": 4127,
"key": "pg/main.dump",
"region": "ru"
},
{
"id": "ev_918452",
"type": "retention.changed",
"at": "2026-07-30T21:04:18Z",
"keep": 30
}
]
}
Параметр wait задаётся в секундах, максимум — 3600. Значение по умолчанию 900: оно проходит через большинство промежуточных шлюзов, которые рвут молчащее соединение на пятнадцатой минуте.
#Курсор и порядок
Каждый ответ несёт cursor — позицию агента в ленте событий. Следующий запрос должен прийти с этим значением, иначе агент получит события заново.
События упорядочены и не теряются: лента хранится 72 часа, поэтому агент, отсутствовавший сутки, получит всё пропущенное по своему курсору. Если курсор старше срока хранения, сервер вернёт 410 с кодом E1203 — это сигнал сделать полную сверку состояния вместо чтения ленты.
Доставка — «как минимум один раз». Одно и то же событие может прийти дважды, если агент упал между получением и сохранением курсора. Обрабатывайте события идемпотентно, ориентируясь на поле id.
#Типы событий
| Тип | Когда приходит | Что делает агент |
|---|---|---|
job.scheduled | наступило время копии по расписанию | открывает сессию передачи |
job.cancelled | задание снято администратором | отменяет сессию, если успел открыть |
restore.requested | запрошено восстановление версии | начинает выгрузку с Range |
token.revoked | токен агента отозван | прекращает работу, чистит кэш |
retention.changed | изменена политика хранения | обновляет локальную копию политики |
region.readonly | регион переведён в режим чтения | откладывает копии, восстановление продолжает |
Неизвестные типы событий нужно игнорировать, а не считать ошибкой: мы добавляем их без смены версии канала, и агент, который падает на незнакомом типе, ломается на ровном месте.
#Легаси-канал v2
/api/v2/sync работает и будет работать до 1 марта 2027 года. Он нужен агентам версии 1.3 и старше — их всё ещё заметно на контурах, где обновление проходит раз в год по регламенту.
curl -N "https://vault.goida.fun/api/v2/sync?since=2026-07-30T20:00:00Z" \
-H "Authorization: Bearer vlt_ag_7Q2m4Xd9pKcRt6Yb"
Отличий три, и все они — причины, по которым появился v3:
- вместо курсора — метка времени
since; после разрыва агент переприсылает себе события за сутки и обрабатывает их повторно; - потолок удержания соединения — 300 секунд, дальше обязательное переподключение;
- нет типов
region.readonlyиretention.changed— старые агенты о них просто не узнают.
После 1 марта 2027 канал начнёт отвечать 410. Отдельного «дня отключения» с сюрпризом не будет: за два месяца до даты в ответы v2 добавится заголовок X-Vault-Sunset, и мы напишем администраторам пространств, где такие агенты ещё живы.
#Настройка таймаутов
Если между агентом и сервисом стоит промежуточный шлюз, его таймаут на простаивающее соединение должен быть больше, чем wait. Иначе картина выглядит так: агент ждёт полчаса, шлюз рвёт связь на пятнадцатой минуте, агент считает это ошибкой сети и переподключается — и так по кругу.
- wait по умолчанию
- 900 с
- wait максимум
- 3600 с
- удержание в v2
- 300 с
- хранение ленты
- 72 ч
- пауза перед повтором
- от 2 до 45 с
- каналов на агента
- 1
Второй одновременный канал на тот же токен получит 409: лента у агента одна, и два читателя с разными курсорами неизбежно разъедутся.