Как реализовать outbox: таблица, отправщик и дедупликация
Проблема двойной записи в том, что «сохранить в базу» и «отправить в брокер» — две операции без общей транзакции: упало между ними, и состояние есть, а события нет (или наоборот). Outbox решает это тем, что событие пишется в ту же транзакцию, в таблицу outbox, а отправкой занимается отдельный процесс. Реализаций две. Опрос таблицы: воркер выбирает неотправленные строки (FOR UPDATE SKIP LOCKED), публикует и помечает; просто, работает везде, даёт задержку в размер интервала опроса и нагружает базу. CDC-коннектор (Debezium с трансформацией outbox): читает журнал изменений, публикует автоматически, задержка миллисекунды и никакой нагрузки запросами — но требует логической репликации, эксплуатации коннектора и внимания к слоту. Обе схемы дают at-least-once, поэтому идентификатор события обязателен, а потребитель обязан быть идемпотентным. Отдельная задача — чистка таблицы: без неё outbox становится самой большой таблицей базы.