Как гарантировать консистентность данных — что сообщение и сохранится в БД, и будет доставлено получателю?
Ответ от нейросети
sobes.tech AI
Для гарантии консистентности данных, чтобы сообщение и запись в базе данных были согласованы (то есть либо оба сохранены, либо ни один), применяют паттерны, обеспечивающие атомарность между базой и системой сообщений.
Основные подходы:
-
Transactional Outbox — в рамках одной транзакции сохраняется и основная бизнес-данные, и сообщение в специальной таблице outbox. Затем отдельный процесс читает и отправляет сообщения.
-
Two-Phase Commit (2PC) — распределённая транзакция между базой и брокером сообщений, но часто сложна и снижает производительность.
-
Idempotent Consumers и повторная отправка — если невозможно атомарно, то делают отправку сообщений с возможностью повторной обработки без побочных эффектов.
В Go можно реализовать transactional outbox примерно так:
func SaveDataAndOutbox(db *sql.DB, data Data, message Message) error {
tx, err := db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
// Сохраняем данные
_, err = tx.Exec("INSERT INTO data_table (...) VALUES (...)", ...)
if err != nil {
return err
}
// Сохраняем сообщение в outbox
_, err = tx.Exec("INSERT INTO outbox (event_type, payload) VALUES (?, ?)", message.Type, message.Payload)
if err != nil {
return err
}
return tx.Commit()
}
Таким образом, либо и данные, и сообщение сохранятся, либо не сохранятся вовсе.