Skip to content

REL-6: Transactional Outbox для Kafka #92

Description

@ii-reviewer

Цель: гарантировать, что событие LowStockAlert не теряется при краше приложения после коммита БД.
Зависимость: KAFKA-1, KAFKA-2.

Проблема

Сейчас producer шлёт событие в TransactionSynchronization.afterCommit(). Если приложение падает сразу после коммита движения, но до отправки в Kafka — событие теряется навсегда; @Retryable живёт только в памяти и краш не переживает. At-least-once не гарантирован: алерт о низком остатке может пропасть.

Что сделать

  • Таблица outbox (id, тип события, payload JSON, статус/флаг отправки, created_at).
  • Событие писать в outbox в той же транзакции, что и stock_movements — атомарно с бизнес-данными.
  • Отдельный релей (планировщик, polling по неотправленным) публикует в Kafka и помечает отправленным после подтверждения брокера.
  • Консьюмер (KAFKA-2) делает дедуп по идемпотентному ключу события — повтор не плодит дубли в stock_alerts.
  • Стретч: явно обеспечить at-least-once + идемпотентный консьюмер; сравнить polling vs CDC (Debezium) с trade-off; продумать, чтобы два инстанса релея не отправили одно событие дважды (lock/SKIP LOCKED).

Acceptance criteria

  • Событие и движение коммитятся атомарно: нет движения без строки в outbox.
  • Краш после коммита, до публикации → после рестарта релей дослал событие (тест с симуляцией сбоя).
  • Повторная доставка не создаёт дубль в stock_alerts (дедуп на консьюмере).
  • Отправленные события помечаются и не шлются повторно при штатной работе.
  • В PR обоснован выбор polling vs CDC.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingkafkaKafka события

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions