Для решения какой архитектурной задачи применяется паттерн Outbox?

«Для решения какой архитектурной задачи применяется паттерн Outbox?» — вопрос из категории Архитектура, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Паттерн Outbox (или Transactional Outbox) решает проблему надежной отправки сообщений/событий в рамках распределенной транзакции между базой данных и брокером сообщений (например, Kafka, RabbitMQ).

Задача: В микросервисной архитектуре часто нужно обновить базу данных И отправить событие о этом изменении. Если сделать это последовательно, возможна ситуация, когда:

  1. Данные в БД сохранены.
  2. Отправка события в брокер завершилась ошибкой. В результате система становится несогласованной.

Решение Outbox:

  1. В рамках одной транзакции с основным бизнес-действием приложение записывает событие в специальную таблицу outbox в той же БД.
  2. После коммита транзакции отдельный процесс-реле (Message Relay) забирает новые записи из outbox и публикует их в брокер сообщений.
  3. После успешной публикации запись из outbox удаляется или помечается как отправленная.

Пример структуры таблицы outbox:

CREATE TABLE outbox (
    id BIGSERIAL PRIMARY KEY,
    aggregate_id UUID NOT NULL, -- ID связанной сущности
    event_type VARCHAR(255) NOT NULL, -- e.g., "UserCreated"
    payload JSONB NOT NULL, -- Данные события
    created_at TIMESTAMP NOT NULL,
    sent_at TIMESTAMP NULL -- Отметка об успешной отправке
);

Этот паттерн гарантирует, что каждое событие будет доставлено как минимум один раз (at-least-once delivery) и является ключевым для реализации надежной асинхронной коммуникации между сервисами.