Ответ
В проекте использовался паттерн «транзакционность базы данных и отправки сообщений» для гарантии согласованности между состоянием БД и отправленными событиями.
Основной подход (Spring Kafka + @Transactional):
@Service
public class OrderService {
@Transactional // Транзакция управляется Spring
public void createOrder(Order order) {
// 1. Сохраняем заказ в БД
orderRepository.save(order);
// 2. Отправляем событие в Kafka.
// Если на предыдущем шаге произойдет исключение, транзакция откатится и сообщение не будет отправлено.
kafkaTemplate.send("order-events", order.getId(), new OrderCreatedEvent(order));
}
}
Для работы требуется настройка KafkaTransactionManager и ChainedKafkaTransactionManager (или JpaTransactionManager) для объединения транзакций.
Паттерн Transactional Outbox для повышенной надежности:
- Событие сохраняется в ту же БД-транзакцию в специальную таблицу
outbox. - Отдельный процесс (например, Debezium или scheduled task) читает из
outboxи публикует события в Kafka. Это гарантирует доставку даже при длительных простоях брокера.
Важно: Этот подход обеспечивает «at-least-once» доставку. Для идемпотентности потребителей необходимо использовать уникальные идентификаторы сообщений (idempotent producer).