← Назад к блогу
Системная архитектура 26.04.2024·4 мин чтения

Transactional Outbox: надёжная интеграция без гонок и потерь

Как гарантировать доставку событий после изменения данных: без двухфазных транзакций и без магии.

Проблема знакомая: запись в БД прошла, а публикация события в брокер — нет. Или наоборот.

Transactional Outbox решает это через простой принцип: сначала атомарно фиксируем данные и событие в одной БД-транзакции, отправляем в брокер асинхронно.

Проще говоря

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

Почему это работает

Внутри одной транзакции вы делаете:

  1. бизнес-изменение (например, order.status = paid),
  2. запись события в outbox_events.

После коммита отдельный publisher читает outbox и отправляет событие в очередь/топик.

Минимальная схема outbox

Поля таблицы:

  • id,
  • event_type,
  • aggregate_id,
  • payload,
  • status (new/sent/failed),
  • available_at,
  • attempts,
  • created_at.

Поток обработки

  1. Приложение пишет данные + outbox в одной транзакции.
  2. Publisher забирает пачку new событий.
  3. Публикует в брокер.
  4. Отмечает sent (или failed + retry).

Ключевые детали

  • Publisher должен быть idempotent.
  • Consumers тоже должны быть idempotent.
  • Нужен retry с backoff и DLQ.
  • Нужен reaper/cleanup старых sent записей.

Частые ошибки

  1. Пишут в outbox вне транзакции.
  2. Отмечают sent до подтверждения публикации.
  3. Нет контроля duplicate delivery.
  4. Нет алертов по stuck/failing outbox.

Production-чеклист

  • атомарная запись бизнес-данных + outbox
  • batch publisher с lock/lease
  • retry/backoff + DLQ
  • метрики: publish latency, failure rate, queue backlog
  • очистка sent событий по retention

Короткая история из команды

Самый полезный шаг оказался самым простым: закрепить договорённость в процессе разработки, чтобы правило работало каждый день, а не только в обсуждениях.

Вывод

Transactional Outbox — один из самых дешёвых и надёжных способов синхронизировать БД и брокер в реальных продуктах.

Он не убирает все проблемы интеграции, но убирает самый дорогой класс потерь: «данные сохранили, событие потеряли».

Практический сценарий внедрения

Если внедрять подход поэтапно, лучше идти от самого болезненного потока: выбрать один критичный user-journey, зафиксировать текущие метрики и применить изменения только на этом участке. Такой подход снижает риск и даёт быстрый доказуемый эффект для команды.

Метрики, которые важно отслеживать

  • p95/p99 latency для ключевых операций,
  • error rate и доля retry/резервный сценарий,
  • время восстановления после сбоев,
  • стоимость обработки запроса/события,
  • доля регрессий после релизов.

Без метрик даже сильные архитектурные решения быстро превращаются в набор гипотез.

Что обычно идёт не так

  1. Команда пытается внедрить всё сразу вместо поэтапного поэтапный запуск.
  2. Нет владельца архитектурного решения и контроль расслаивается.
  3. Решение есть в документации, но не встроено в CI/CD и runbook.
  4. После внедрения нет регулярного review, и качество снова деградирует.

Пошаговый план на 30 дней

  • Неделя 1: базовый уровень, ограничения, целевые KPI.
  • Неделя 2: внедрение в одном потоке + алерты.
  • Неделя 3: стабилизация, фиксы edge-cases.
  • Неделя 4: масштабирование на соседние модули и обновление стандартов команды.

Термины простыми словами

  • Transactional Outbox — паттерн атомарной записи бизнес-изменения и события в одной транзакции с последующей безопасной отправкой в брокер.
  • Политика повторов — правила повторных попыток (когда, сколько раз и с каким backoff), чтобы не усилить сбой.

Этот блок нужен, чтобы статью можно было читать без предварительного контекста по всем терминам.

Почему это часто проваливается на практике

На бумаге архитектурное решение выглядит логично, но в проде мешают сроки, кросс-командные зависимости и отсутствие явного владельца. Когда решение не встроено в CI, мониторинг и ревью, оно быстро деградирует до «локальной договорённости».

Чтобы этого не было, нужно заранее решить три вещи: кто отвечает за стандарт, как проверяется соблюдение, и в какой момент команда пересматривает подход. Без этого даже сильная архитектурная идея через пару релизов теряет форму.