Доставка, outbox и восстановление
Когда ход завершается, ответ ещё нужно доставить в канал, откуда он пришёл — надёжно и ровно один раз. AiHummer решает это транзакционным outbox, идемпотентными побочными эффектами и восстановлением хода после рестарта. Опциональная шина NATS может нести доставку в крупных развёртываниях.
Гарантированная доставка
Ответ не отправляется встроенно в конце хода. Вместо этого он ставится в очередь outbox в рамках той же работы, что его породила, а воркер доставки забирает его и отправляет в канал-источник. Поскольку ответ надёжно записан до того, как уйти, сбой между «ответ сформирован» и «ответ отправлен» не может его потерять — после рестарта запись outbox всё ещё на месте, и доставка продолжается.
ход формирует ответ
└─▶ постановка в outbox (надёжно)
└─▶ воркер доставки ─▶ канал-источник
└─ подтверждено ─▶ помечено доставленным
Доставка идёт в паре с идемпотентностью, поэтому этот не-менее-однократный воркер даёт ровно-однократное внешнее поведение: resume-стабильный ключ реестра и барьер побочных эффектов гарантируют, что повторно доставленный или переигранный ответ отправится в канал лишь однажды (см. Мультиарендность и идемпотентность).
[!NOTE] «Ровно один раз» здесь описывает внешне видимый результат: пользователь получает ответ один раз. Внутри воркер может пытаться доставить более одного раза; слой идемпотентности сворачивает эти попытки в одну видимую отправку.
Восстановление хода после рестарта
Если gateway перезапускается посреди хода — деплой, сбой, перезагрузка хоста, — работа не бросается. Восстановление хода переигрывает прерванный ход, чтобы он завершился. Это безопасно только потому, что побочные эффекты идемпотентны: любая почта или отправка в канал, уже случившаяся до рестарта, распознаётся по своему ключу реестра и пропускается, а несостоявшиеся части доводятся до конца. Пользователь видит единый, полный ответ, а не наполовину готовый или дубль.
Опциональная шина NATS
По умолчанию доставка работает полностью через PostgreSQL, что сохраняет минимальное развёртывание в составе одного gateway плюс база. Для крупных или многошлюзовых конфигураций доставку можно вынести на шину NATS, настроив её URL:
# gateway.env
AIHUMMER_NATS_URL=nats://127.0.0.1:4222
Шина по-настоящему опциональна — оставьте AIHUMMER_NATS_URL незаданной, и outbox
работает без неё. Когда она есть, NATS становится транспортом, по которому течёт
работа доставки, что подходит горизонтально масштабируемым gateway за прокси.
[!TIP] Обновления без простоя запускают два и более gateway за обратным прокси. Планировщик остаётся единственным лидером через advisory-лок Postgres, а идемпотентная доставка означает, что дополнительные gateway могут делить нагрузку, ничего не отправляя дважды.
За чем следить
Доставка — это место, где проблемы надёжности проявляются первыми, поэтому именно
её и нужно мониторить. AiHummer пушит телеметрию по OTLP
(AIHUMMER_OTEL_ENDPOINT) и поставляет дашборды Grafana; эндпоинта Prometheus
/metrics для скрейпа нет.
- Диспозиции доставки (delivery dispositions) — исход каждой попытки доставки. Рост числа отказов указывает на проблему канала или нижележащего сервиса.
- Глубина outbox — сколько ответов ждут доставки. Устойчивый рост означает, что доставка отстаёт.
- Глубина DLQ — записи, исчерпавшие ретраи и попавшие в очередь недоставленных (dead-letter queue). Любой рост DLQ заслуживает разбирательства.
[!WARNING] Следите за этим вместе с задержкой хода и долей ошибок. Растущий outbox или DLQ — раннее предупреждение о деградации нижележащих каналов, даже когда сами ходы ещё проходят успешно.
Куда дальше
- Идемпотентность, делающая доставку ровно-однократной: Мультиарендность и идемпотентность.
- Движок, который вообще формирует ответ: Gateway и turn-движок.