Сначала ответь вслух
Скажи ответ вслух хотя бы пару минут, потом открой эталон и сравни. Эталон открыт всем и не требует входа.
Показать ответ
Эталонный ответ
Отправка после коммита может не случиться: сервис упал между двумя действиями, и событие потеряно. Отправка до коммита хуже: транзакция откатилась, а событие уже ушло.
@Transactional
public void placeOrder(Order order) {
orders.save(order);
outbox.save(new OutboxEvent(order.id(), "OrderPlaced", json(order)));
}
// Отдельный процесс читает outbox, публикует в Kafka и отмечает отправленноеПубликатор читает таблицу опросом или через захват изменений из журнала базы. Если он упадёт после отправки, но до отметки, событие уйдёт повторно. Ключ сообщения — id заказа: тогда события одного заказа попадут в одну партицию и сохранят порядок.
Как у тебя получилось?
Уточняющие вопросы
Так обычно копают глубже. Раскрой строку, когда ответишь вслух.
Уточнение 1-го уровня: Что выбрать: опрос таблицы или захват изменений?
Ответ уровня Senior
Опрос проще и не требует инфраструктуры, но нагружает базу и добавляет задержку. Захват изменений читает журнал предзаписи, быстрее и легче для базы, но это ещё один компонент в эксплуатации.
Уточнение 2-го уровня: Как потребителю не обработать событие дважды?
Ответ уровня Senior
Хранить id обработанных событий в таблице с уникальным ключом и вставлять его в той же транзакции, что и результат обработки. Повтор упрётся в ключ и будет пропущен.
Типичные ошибки
- Отправлять в Kafka внутри @Transactional и считать это атомарным.
- Не делать потребителя идемпотентным.
Первоисточники
Быстрые задания по теме
Для темы «Transactional outbox» быстрых заданий пока нет
Можно проверить всю зону «Согласованность данных» тестом на 10 минут.
Проверить себя за 10 минут