> Как обнаруживать и реагировать на проблемы с отменой брони (Go)
Уровень: senior · Роль: backend · Категория: Технические вопросы
Компании: sferaplatform.ru
Стек: Go
> Пример ответа
Короткий ответ
Обнаружение проблем с отменой брони строится на трёх уровнях: трассировка отмены через контекст, мониторинг времени выполнения операций и алерт-система на основе метрик. Реагирование - это graceful shutdown, повторные попытки с backoff для идемпотентных операций и компенсационные транзакции. Ключевой момент - не игнорировать отмену, а явно проверять ctx.Err() после каждого потенциально блокирующего вызова и логировать, где именно произошла отмена, с полным стеком операций.
Подробное объяснение
Проблемы с отменой брони в Go обычно проявляются в трёх сценариях:
-
Потерянная отмена - контекст не пробрасывается через все слои приложения, и операция продолжает выполняться после отмены. Это приводит к лишней нагрузке на БД, внешние сервисы и утечкам горутин.
-
Зависшая отмена - операция не реагирует на
ctx.Done(), потому что использует блокирующие вызовы без учёта контекста (например,time.Sleep,db.Queryбез контекста,http.Getбез контекста). -
Частичная отмена - отмена происходит между шагами распределённой операции, и часть шагов уже выполнена, а часть нет. Требуется компенсация.
Обнаружение строится на:
- Инструментировании: каждый слой приложения логирует
ctx.Err()при завершении операции. Еслиctx.Err() != nil, это событие для метрик. - Метриках: гистограмма времени выполнения операций с тегом
canceled=true/false. Резкий рост доли отменённых операций - сигнал к алерту. - Трассировке: OpenTelemetry-спаны с атрибутом
canceled=trueпозволяют увидеть, где именно в цепочке вызовов произошла отмена. - Структурированном логировании: при отмене логируем
operation_id,cancel_reason(deadline exceeded, client closed connection, parent canceled),duration,stackна уровне debug.
Реагирование:
- Graceful shutdown: при сигнале отмены завершаем текущие операции, но не начинаем новые. Используем
errgroupс контекстом для координации. - Retry с умным backoff: если операция идемпотентна, повторяем с экспоненциальным backoff, но только если отмена не была вызвана клиентом. Для этого различаем
context.Canceledиcontext.DeadlineExceeded. - Компенсация: для распределённых операций храним состояние шагов и при отмене выполняем обратные действия (например, возврат средств, освобождение ресурсов).
- Circuit breaker: если доля отмен превышает порог, размыкаем цепь и не пускаем новые запросы, чтобы не усугублять нагрузку.
На практике
В реальном сервисе бронирования:
- Все репозитории принимают
ctxпервым аргументом и используютQueryContext,ExecContext,BeginTxс контекстом. - HTTP-хендлеры проверяют
r.Context().Err()перед отправкой ответа - если клиент отключился, не пишем вResponseWriter. - Фоновая обработка (например, подтверждение брони через email) использует
errgroup.WithContextи при отмене отменяет все дочерние задачи. - Метрики:
canceled_operations_total{operation, reason}иoperation_duration_seconds{operation, canceled}. - Алерт: если
rate(canceled_operations_total[5m]) > 0.1 * rate(operations_total[5m])- паника в сервисе или проблема с upstream.
Пример реакции на отмену в middleware:
GOfunc CancelMiddleware(next http.Handler) http.Handler {return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {ctx := r.Context()done := make(chan struct{})go func() {select {case <-ctx.Done():// клиент отключился - логируем и прекращаем работуlog.WithContext(ctx).Warn("client disconnected","path", r.URL.Path, "err", ctx.Err())// не пишем в w - это вызовет panic, если уже писалиcase <-done:}}()next.ServeHTTP(w, r.WithContext(ctx))close(done)})}
Как отвечать на собеседовании
Начните с того, что отмена - это не ошибка, а нормальное состояние системы. Покажите, что различаете context.Canceled и context.DeadlineExceeded - это разные сценарии с разной реакцией. Обязательно упомяните, что проверка ctx.Err() должна быть после каждого блокирующего вызова, а не только в начале функции. Расскажите про метрики и алерты - интервьюер хочет услышать, что вы думаете о наблюдаемости, а не только о коде. Хорошо добавить пример из практики: как вы находили утечку горутин из-за потерянного контекста через pprof и трассировку.
Что проверяет интервьюер
- Понимание жизненного цикла контекста и его проброса через все слои.
- Умение различать типы отмен и выбирать стратегию реакции.
- Навыки наблюдаемости: метрики, логи, трассировка.
- Понимание компенсационных транзакций в распределённых системах.
- Практический опыт с
errgroup,context.WithTimeout,context.WithCancel.
Типичные ошибки
- Проверка
ctx.Err()только в начале функции - отмена может произойти в середине. - Использование
time.Sleepвместоselectсctx.Done(). - Игнорирование отмены в фоновых горутинах - они продолжают работать после завершения запроса.
- Retry без проверки причины отмены - повторяем даже когда клиент ушёл.
- Логирование отмены как ошибки - это засоряет алерты и скрывает реальные проблемы.
- Не различать
context.Canceledиcontext.DeadlineExceeded- это разные сценарии: клиент отключился vs таймаут.
> Похожие задачи по backend
Расскажи про последнее место работы, задачи и архитектуру
Сколько разработчиков в команде, на каких языках они работают и как устроена команда
Как обрабатывать ошибки при отмене брони на складе
Как снять бронь товара при отмене заказа
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью