Здесь небезопасная сборка SQL и неатомарность между UPDATE и публикацией события. Параметризуйте запрос и записывайте событие в outbox в той же транзакции.
func (r *PayoutRepository) save(p Partner) error {
Здесь небезопасная сборка SQL и неатомарность между UPDATE и публикацией события. Параметризуйте запрос и записывайте событие в outbox в той же транзакции.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
func (r *PayoutRepository) save(p Partner) error { _, err := r.db.Exec( fmt.Sprintf("UPDATE partners SET balance = %s, hold = %s WHERE id = %s", p.Balance, p.Hold, p.ID), ) if err != nil { return err } if err := r.eventPublisher.Publish("BalanceChanged", p); err != nil { return err } return nil }
Ответ
Здесь небезопасная сборка SQL и неатомарность между UPDATE и публикацией события. Параметризуйте запрос и записывайте событие в outbox в той же транзакции.
fmt.Sprintf с %s не подходит произвольным числовым типам и допускает опасную интерполяцию ID. Используйте параметры драйвера, точные денежные значения, context и проверку RowsAffected. Если Publish упал после UPDATE, данные уже изменены; повтор может создать несогласованность или дубликат события. Outbox фиксирует намерение публикации вместе с изменением, а отдельный отправитель повторяет доставку с устойчивым event_id. Сам UPDATE также должен сохранять бизнес-инварианты конкурентных операций.