func (r *PayoutRepository) Payout(advertiserID, partnerID string, amount float32) error {

Выплату нужно выполнять одной транзакцией с защитой обеих записей от конкурентных изменений. float32 для денег и локальный счётчик totalPayouts создают дополнительные риски.

Короткий ответ

Что ответить на собеседовании

Выплату нужно выполнять одной транзакцией с защитой обеих записей от конкурентных изменений. float32 для денег и локальный счётчик totalPayouts создают дополнительные риски.

Подробный разбор

Ответ с пояснениями

Условие

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  // защитить SELECT FOR UPDATE
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 для денег и локальный счётчик totalPayouts создают дополнительные риски.

Используйте целые минимальные единицы или decimal, проверяйте amount>0 и достаточность balance/hold. SELECT FOR UPDATE выполняйте через одну tx с одинаковым порядком блокировки идентификаторов во всех вызовах. Обработайте случай одинаковых сторон.

Сохранения также должны идти через tx; Commit проверяется, Rollback предусмотрен. Повтор платежной команды защищают уникальным ключом. Счётчик в памяти не заменяет транзакционную запись факта выплаты.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее