Explanation: архитектура и принципы¶
Зачем система устроена именно так. Это разбор идей, не инструкция и не справочник.
Полный текст — event-bus-concept.md в корне; здесь — суть и границы.
Два слоя, граница по событию¶
- Шина (NATS JetStream) отвечает на «что произошло»: факты, межсистемная связь, персистентность. Хребет.
- Движок (Inngest и др.) отвечает на «что с этим сделать, надёжно и по шагам»: оркестрация, состояние, ретраи.
Событие живёт в шине. Его обработка живёт в движке. Граница проходит по событию.
Движок — участник шины через тонкий мост, а не центр. Нейтральная точка — всегда шина; движок сменяем, не трогая контракт.
Три плана, не свалка в одном стеке¶
Топология разведена по сетям, и это не косметика — это та же граница, что и в концепте, выраженная в деплое:
- Шина (
event-bus) — NATS. Сюда подключаются разнородные участники (stacks/integrations) и мост. - План движка (
engine) — connect-gateway Inngest и OUT-эндпойнт моста (/publish). Сюда смотрят durable-воркеры (stacks/functions). NATS тут нет. - Приватное (
internal) — хранилища движка (postgres/redis), наружу не светятся (ADR 0001).
Ключевой вывод: воркер-функция — это «рука движка», а не сервис на шине. Её
вызывает движок (connect), результат она отдаёт только через мост, NATS она не
трогает. Поэтому воркеры живут своим стеком на плане engine, а stacks/bus
остаётся чистой инфраструктурой — новый воркфлоу не правит инфра-стек. Раньше
воркеры лежали внутри bus лишь потому, что у движка не было разделяемого плана;
сеть engine это чинит, не нарушая «Inngest не на шине» (events через границу —
по-прежнему только мостом; воркеру даже не выдаётся event-key).
Контракт — единственная связанность¶
Участники разнородны (разные языки, стеки, внешние). Их объединяет только контракт: subject'ы, схемы, correlation, durability-конвенции. Никаких прямых вызовов между участниками — реакция на факты. Это и даёт расширяемость: добавление/удаление участника — рутина (см. how-to), потому что ничего, кроме контракта, не связывает.
Чтобы это держалось, контракт — ворота: валидация схем и каталог в CI (#3), версионирование при ломающих изменениях (#4). Шаблоны делают соблюдение дешёвым; ворота делают нарушения видимыми.
Рантайм-агностичность¶
Шине всё равно, на чём участник — Go/TS/Python, декларативный Benthos, движок Inngest/Windmill, managed-compute Modal. Выбор инструмента — по потребности, а не по моде (ADR 0002). Внутреннее состояние участника приватно (ADR 0001).
Надёжность и наблюдаемость¶
At-least-once шины + идемпотентность участников = безопасные повторы. Мост держит
4 правила (детерминированный id, ack-после-2xx, бэкпрешер, дедуп выхода).
Застрявшее уходит в DLQ. Отладка — сквозная: traceparent через весь путь,
трейсы в Jaeger (наблюдаемость).
Наращивание по мере боли¶
Слои добавляются, когда боль реальна (концепт, раздел 10), кроме невозвратного фундамента (брокер с персистентностью, именование, correlation ID, контракт в git). Каталог — когда участников несколько; версионирование — на первом ломающем; трейсинг/DLQ — когда отладка становится болью. Так система не переусложняется вперёд нужды.