Ответ
Используйте паттерн Saga или Transactional Outbox. В Golang можно реализовать через:
- Транзакционность БД + Outbox:
func ProcessOrder(ctx context.Context, order Order) error {
tx, _ := db.BeginTx(ctx, nil)
defer tx.Rollback()
// 1. Сохраняем заказ в БД
if err := SaveOrder(tx, order); err != nil {
return err
}
// 2. Сохраняем событие в outbox таблицу
event := OutboxEvent{
Type: "OrderCreated",
Payload: order,
}
if err := SaveOutboxEvent(tx, event); err != nil {
return err
}
// 3. Коммитим транзакцию
return tx.Commit()
}
- Компенсирующие транзакции (Saga):
- Для каждого шага определяем компенсирующее действие
- При ошибке выполняем цепочку компенсаций
- Идемпотентность обработчиков:
- Повторная отправка не должна вызывать дублирование эффекта
Дополнительно можно использовать:
- Периодическую проверку статуса (health checks)
- Таймауты и retry-логику
- Dead Letter Queue для проблемных сообщений