data[i] = &backentry{

В ветке entry == nil mutex не освобождается, поэтому следующий Invoke зависнет. Нужно разблокировать его перед возвратом, сохраняя сетевой вызов вне критической секции.

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

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

В ветке entry == nil mutex не освобождается, поэтому следующий Invoke зависнет. Нужно разблокировать его перед возвратом, сохраняя сетевой вызов вне критической секции.

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

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

Условие

data[i] = &backentry{ backend: NewBackend(addr), inflight: 0, }

return &Balancer{ backends:data, mu: &sync.Mutex{}, }

func(b *Balancer) Invoke(ctx context.Context, req Request) (Response, error){ b.mu.Lock() entry := b.best() if entry == nil{ return nil,errors.New("no backend") } entry.inflight++ b.mu.Unlock()

defer func(){
    b.mu.Lock()
    entry.inflight--
    b.mu.Unlock()
}()

return entry.backend.Invoke(ctx,req)

}

func(b *Balancer) best() *backentry{ var best *backentry for _,entry := b.backends{ if best == nil || entry.inflight < best.inflight{ best = entry } } return best }

Ответ

В ветке entry == nil mutex не освобождается, поэтому следующий Invoke зависнет. Нужно разблокировать его перед возвратом, сохраняя сетевой вызов вне критической секции.

Исправляемый участок:

b.mu.Lock()
entry := b.best()
if entry == nil {
    b.mu.Unlock()
    var zero Response
    return zero, errors.New("no backend")
}
entry.inflight++
b.mu.Unlock()

Оставшийся defer уменьшает inflight после Invoke. best должен вызываться под тем же lock, а изменение списка backends — синхронизироваться. Нельзя просто отложить Unlock до конца функции: тогда сетевой вызов удержит mutex и сериализует запросы.

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

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

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

Подробнее