← HTTP API

Живые обновления

http api · push-канал · workzone

Статусные борды показывают состояние, которое мутируют фоновые воркеры — sync-прогоны, curation-прогоны, бэкапы, прогоны агентов. Экран не мутирует то, что показывает, поэтому инвалидация кеша по действиям пользователя его не обновит, а поэкранные таймеры опроса не масштабируются. Все их заменяет один платформенный push-канал.

Пушим факт изменения, не данные
SSE как сигнал инвалидации Поток несёт крошечный сигнал — «борд X изменился» — и ничего больше. Клиент в ответ рефетчит затронутые запросы через обычные REST-эндпоинты, которыми уже пользуется. Данные, auth и ACL остаются на REST: поток не может утечь пейлоадом, не дрейфует от REST-схемы, а нагрузка на бэкенд пропорциональна реальным изменениям состояния — не числу открытых экранов.
Воркер переход прогона или коммит прогресса
Publish сигнал → pub/sub cache-Redis, после commit
Поток /events/stream — один SSE на вкладку
Клиент инвалидирует query-ключи борда
REST обычный рефетч — auth, ACL, схема

Канал едет на pub/sub cache-Redis — потерянный сигнал стоит одного отложенного обновления, никогда — данных. Публикация best-effort: сломанная шина не должна валить транзакцию самого воркера.

Контракт событий — GET /api/v1/events/stream

Один мультиплексный поток на вкладку несёт все push-заботы; колокольчик уведомлений тоже едет в нём, так что платформа держит единственное постоянное соединение. Диспетчер публикует сигналы колокольчика ровно как раньше — общим стал только транспорт.

СобытиеПейлоадСмысл
hello {boards: […]} открывает поток: борды, на которые подписан вызывающий. Клиент инвалидирует их все — reconnect нагоняет всё пропущенное.
board {board} названный борд изменился; клиент инвалидирует его query-ключи по реестру.
unread {count} счётчик колокольчика, рефетчится на сервере по сигналу колокольчика — поведение прежнее, транспорт новый.
ping {} heartbeat после 25 с тишины — настоящий event-фрейм, не SSE-комментарий, чтобы клиентский watchdog видел живость.
Борды и кто их получает

Доступ решается в момент подписки: при открытии потока роль вызывающего выбирает набор каналов — админские борды админам, канал агентов владельца каждому. Никакой пофреймовой фильтрации, никакого пер-юзерного fan-out для админских бордов.

БордКормится изАудитория
harvester журнал sync-прогонов Harvester + постраничные счётчики прогресса админы
knowledge curation-прогоны · прогресс re-embed · бэкапы Knowledge Store админы
agents журнал прогонов Agent Engine, включая шаги владелец агента — свой канал; админы — канал всех агентов
Точки публикации и коалесинг

Что публикует. Каждый закоммиченный переход прогона (queued → running → терминальный, отмена) и каждая закоммиченная запись прогресса по ходу — граница страницы синка, батч re-embed, шаг агента. Публикация идёт после commit, поэтому сигнал никогда не анонсирует состояние, которого рефетч ещё не увидит.

Что не публикует. Чистые heartbeat-касания — учёт живости не изменение состояния и не должен будить каждый открытый экран.

Коалесинг — забота подписчика. Воркеры публикуют свободно — publish в Redis почти бесплатен; каждое соединение потока коалесцирует по борду с минимальным зазором эмиссии 1.5 с, по задней кромке (всплеск даёт один фрейм сразу и один по истечении зазора). Горячий цикл воркера не заставит клиента рефетчить чаще зазора, а последнее состояние доедет всегда.

Клиент — одно соединение, один реестр

Шелл монтирует единственного потребителя потока с декларативным реестром борд → префиксы query-ключей. Фрейм board инвалидирует префиксы этого борда; рефетчатся только реально смонтированные запросы. Экраны не несут никакого кода живых обновлений — ни таймеров, ни интервалов: экран живой потому, что его ключи в реестре, а не потому, что он опрашивает.

Fallback — тихая деградация
Единственное исключение — веса эмбеддера

Загрузка весов встроенного эмбеддера — единственный живой статус, живущий вне базы платформы: внутри embeddings-рантайма, который бэкенд лишь проксирует. Нашего перехода, из которого публиковать, нет — поэтому карточка эмбеддера сохраняет узкий опрос только пока грузятся веса. Всё остальное на каждом борде — push. Второй статус такого рода оправдал бы серверного наблюдателя; один — нет.