Выплата должна быть атомарной и идемпотентной: деньги нельзя хранить в float32, а независимые save допускают частичное обновление и гонки.
func (r *PayoutRepository) Payout(advertiserID, partnerID string, amount float32) error {
Выплата должна быть атомарной и идемпотентной: деньги нельзя хранить в float32, а независимые save допускают частичное обновление и гонки.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
func (r *PayoutRepository) Payout(advertiserID, partnerID string, amount float32) error { advertiser, err := r.find(advertiserID) if err != nil { return err } partner, err := r.find(partnerID) if err != nil { return err }
advertiser.Balance -= amount
partner.Hold -= amount
partner.Balance += amount
if err := r.save(advertiser); err != nil {
return err
}
if err := r.save(partner); err != nil {
return err
}
r.totalPayouts++
return nil
}
Ответ
Выплата должна быть атомарной и идемпотентной: деньги нельзя хранить в float32, а независимые save допускают частичное обновление и гонки.
Используйте целые минимальные денежные единицы или точный decimal. Проверьте положительность суммы, доступный баланс и смысл списания Hold: текущий код может делать его отрицательным. Обновляйте счета в одной транзакции, блокируя их в стабильном порядке; случай совпадения advertiserID и partnerID обработайте отдельно. Уникальный ключ операции защищает от повторной выплаты. totalPayouts++ также гоняется между потоками и не является надёжным финансовым журналом; успешные выплаты лучше учитывать по зафиксированным операциям.