Что такое паттерн Outbox и зачем он нужен в микросервисах
Что проверяют
Понимаете ли вы задачу двойной записи: сервис меняет свою базу и обязан сообщить об этом другим, а двух надёжных операций в одной транзакции не бывает. Ждут объяснения, почему отправка в брокер после фиксации транзакции и фиксация после отправки одинаково ненадёжны.
Как отвечать
Начните с проблемы. Записали заказ и упали до отправки события: другие сервисы о нём не узнают. Отправили событие первым, а транзакция откатилась: событие есть, заказа нет.
Решение: событие пишется в таблицу исходящих сообщений той же транзакцией, что и бизнес-данные. Атомарность даёт база, брокер в транзакции не участвует. Отдельный процесс читает неотправленные строки, публикует их и помечает отправленными. Вариант без опроса таблицы: изменения вычитываются из журнала базы средствами захвата изменений и уходят в топик.
CREATE TABLE outbox (
id bigint GENERATED ALWAYS AS IDENTITY,
aggregate_id text NOT NULL,
type text NOT NULL,
payload jsonb NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
sent_at timestamptz
);Важные детали: доставка получается «хотя бы один раз», поэтому у события нужен идентификатор, а у получателя обработка, устойчивая к повторам; ключом сообщения берут идентификатор сущности, чтобы её события сохраняли порядок; отправленные строки чистятся по расписанию; при нескольких экземплярах отправителя строки забираются с блокировкой и пропуском занятых.
Где спотыкаются
Публикуют событие прямо из кода бизнес-операции и считают, что отправка сразу после фиксации это и есть надёжность. Процесс умирает между фиксацией и отправкой, и событие теряется навсегда.
Ждут ровно одной доставки. Outbox гарантирует, что событие не потеряется, но не то, что оно придёт один раз; без идемпотентности у получателя появляются двойные списания и повторные письма.
Забывают про уборку и про порядок. Таблица исходящих без очистки становится самой большой в базе, а отправка в несколько потоков без ключа перемешивает события одной сущности, и получатель видит отмену раньше создания.