x/sync/semaphore и отмена
Rate limiter победил 429, но отменённые клиентом запросы висели в очереди на слот. Миша взял семафор из x/sync: Acquire принимал контекст и выходил по отмене, не занимая разрешение.
golang.org/x/sync/semaphore — семафор с отменой: Acquire(ctx, n) ждёт разрешения и умеет отменяться по контексту, не теряя разрешение.
Acquire с контекстом
sem := semaphore.NewWeighted(8)
if err := sem.Acquire(ctx, 1); err != nil {
return err // отменены, пока ждали
}
defer sem.Release(1)
recognize(ctx, f)
Канал-семафор из умел только блокироваться. У пакетного семафора Acquire принимает контекст: если ctx отменён, пока горутина ждёт разрешения, Acquire возвращает ошибку и не занимает разрешение. Это главное отличие: с каналом горутина могла бы занять токен в момент отмены и утечь вместе с ним.
Где это важно
Сценарий: горутина ждёт свободный слот на вызов внешнего API распознавания, а запрос тем временем отменяют (клиент закрыл вкладку). С каналом-семафором она так и будет висеть в очереди (или займёт токен и зависнет дальше). С Acquire(ctx, 1) — выйдет сразу с ошибкой context.Canceled. Для сервисов, где отмена — норма жизни, это не мелочь, а защита от копящихся «ждунов».
Пара Acquire/Release
if err := sem.Acquire(ctx, 1); err != nil {
return err
}
defer sem.Release(1)
Симметрия: успешный Acquire — и тут же defer Release. Возврат случится при любом выходе из функции, и про парность можно не думать. Успех Acquire — единственная точка, где разрешение занято, поэтому утечка разрешений возможна только при явной ошибке в коде.
Вы узнаете:
- чем пакетный семафор тяжелее канала
- как
Acquireведёт себя при уже отменённом ctx
Проверьте себя
Что делает Acquire(ctx, n) при отмене контекста во время ожидания?
Канал-семафор при отмене ctx во время ожидания слота. Что происходит?
Release без успешного Acquire. Что это?
правильных ответов
x/sync/semaphore: Acquire с контекстом — отмена без потери разрешения; пара Acquire/defer Release. Дальше — веса, ради которых пакет и назван Weighted.
10 000 ₽ · 60 минут · онлайн