// добави $1
Golang
Ако ти сам пишеше единични тестове за своя код, кои би написал? Какви крайни случаи би проверил?
От къде да вземете ID на събитието за идемпотентност и къде да го генерирате?
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 }
Къде съхранявахте логовете, какъв пакет за логиране използвахте в кода и как логовете от stdout достигнаха до Elasticsearch?
Как на ниво SQL да разберем, че вече съществува такъв ключ за идемпотентност? Как да използваме ON CONFLICT?
Разкажи за проекта/вакансията: стек технологии, задачи на екипа
Какви още глобални проблеми има в кода? Как да съхраняваме пари — може ли да се използва float?
Какво ще се случи с ID в outbox, ако транзакцията не бъде потвърдена?
функция (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 }
/* Подреден списък от цели числа a, индекс index и цяло число k. Трябва да върнете произволен ред k числа от списъка, които са най-близки по стойност до елемента a[index]. a=[2, 3, 5, 7, 11], index=3, k=2 -> [5, 7] a=[4, 12, 15, 15, 24], index=1, k=3 -> [12, 15, 15] a=[2, 3, 5, 7, 11], index=2, k=2 -> [3, 5] или [5, 7] */
func (p *Pool) Stop() { p.mu.Unlock() // Сега е безопасно да затворим канала close(p.tasks) // сигнал към работниците: няма да има нови задачи, прочетете остатъка p.wg.Wait() // чакаме всички горутини да приключат p.cancel() // отменяме контекста, ако е необходимо fmt.Println("Pool спря.") } // ForceStop принудително спира всички работници без да чака завършването на задачите. // Работниците ще бъдат прекъснати незабавно чрез контекста. func (p *Pool) ForceStop(timeout time.Duration) { fmt.Printf("Принудително спиране на пула (таймаут: %v)...\n", timeout) // Блокира добавянето на нови задачи p.mu.Lock() p.isOpen = false p.mu.Unlock() // Затваря канала, за да не взимат нови задачи работниците close(p.tasks) // Отменя контекста – това ще прекъсне всички изпълняващи се задачи p.cancel() // Даваме ограничено време за завършване done := make(chan struct{}) go func() { p.wg.Wait() close(done) }() select { case <-done: fmt.Println("Пулът е принудително спрян (всички работници са завършили)") case <-time.After(timeout): fmt.Println("Пулът е принудително спрян (таймаут, може да останат висящи goroutine)") } }
Какъв е проблемът с копирането на sql.DB по стойност, а не по указател?
Колко време са били съхранявани логовете и колко време са били съхранявани данните в Kafka?
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 }
функция (r *PayoutRepository) Payout(автоматиченID, партньорID стринг, сума float32) грешка { рекламодател, грешка := r.find(totalPayouts) // добавяне на транзакция ако грешка != nil { връщане грешка } партньор, грешка := r.find(partnerID) ако грешка != nil { връщане грешка } рекламодател.Баланса -= сума партньор.Hold -= сума партньор.Баланса += сума ако err := r.save(рекламодател); err != nil { връщане err } ако err := r.save(партньор); err != nil { връщане err } r.totalPayouts++ връщане nil } функция (r *PayoutRepository) find(id string) (Partner, грешка) { p := Partner{} err := r.db.QueryRow("SELECT * FROM partners WHERE id = " + id).Scan(&p) // добавете $1 ако err != nil { ако err == sql.ErrNoRows { връщане p, errors.New("партньор не е намерен") } връщане p, err } връщане p, nil }
Извлечете въпроса/задачата от интервюто от този скрийншот. Запазете оригиналния език.
Какво точно да се пише в съобщението Kafka? Какви полета да се предават на потребителите?
Какво са ld, rd := 1<<62, 1<<62 в контекста на алгоритъма?
пакет за съхранение import ( "database/sql" "errors" "fmt" "time" "github.com/company/my-service/internal/event" "github.com/company/my-service/internal/metric" ) type Partner struct { ID string `db:"id" json:"id"` Balance float32 `db:"balance" json:"balance"` Hold float32 `db:"hold" json:"hold"` } type PayoutRepository struct { db sql.DB eventPublisher event.Publisher metricCollector metric.Collector totalPayouts int } func NewPayoutRepository() *PayoutRepository { db, err := sql.Open("postgres", "host=localhost user=postgres password=postgres dbname=affiliate") if err != nil { panic(err) } r := PayoutRepository{ db: db, eventPublisher: event.NewKafkaPublisher("localhost:9092"), metricCollector: metric.NewPrometheusCollector("localhost:9090"), } go func() { for range time.Tick(time.Minute) { _ = r.metricCollector.Send("TotalPayouts", r.totalPayouts) } }() return r } 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 } func (r *PayoutRepository) find(id string) (Partner, error) { p := Partner{} err := r.db.QueryRow("SELECT * FROM partners WHERE id = " + id).Scan(&p) if err != nil { if err == sql.ErrNoRows { return p, errors.New("partner not found") } return p, err } return p, nil } 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 }