Context в Go
Как правильно ждать отмены через Context.Done?
Долгая операция включает ctx.Done() в select рядом с работой или ожиданием. При закрытии канала она прекращает запуск новых действий, освобождает свои ресурсы и возвращает ctx.Err() либо ошибку с сохранённой причиной. Проверку выполняют в местах, где функция способна остановиться; один тест перед началом не отменит уже блокирующий вызов. Downstream API получает тот же context, чтобы отмена дошла до сети и БД. Done может быть nil для context без отмены, и select корректно игнорирует такой case. Функция не должна сама ждать, пока caller прочитает канал.
Ссылки для изучения
Как распространять context через цепочку вызовов?
context.Context передают первым параметром, обычно с именем ctx, через всю цепочку request-scoped вызовов. Функция создаёт дочерний context только для более узкого deadline, отмены или значения и обязательно вызывает полученный CancelFunc. HTTP, SQL и RPC операции получают этот context своими context-aware методами. Его не хранят в struct и не заменяют nil; если контекст пока не нужен, передают context.Background() на верхней границе. Отмена родителя распространяется детям, но ребёнок не отменяет родителя. Контекст живёт не дольше запроса и не используется как контейнер всех параметров.
Ссылки для изучения
Что допустимо хранить в context.WithValue?
В context.WithValue хранят небольшие неизменяемые request-scoped данные, которые передаются по цепочке вызовов: trace ID, аутентифицированного субъекта или метаданные запроса. Ключ задают собственным неэкспортируемым типом, чтобы пакеты не сталкивались по строке. Значение должно быть дополнительным, а не обязательной зависимостью функции. Конфигурацию, logger, БД, feature options и параметры бизнес-метода передают явно. Нельзя складывать изменяемый объект и ожидать потокобезопасности: context безопасен для конкурентного чтения, но не меняет гарантии самого значения.
Ссылки для изучения
Почему нужно вызывать CancelFunc после context.WithTimeout?
WithTimeout создаёт таймер и дочерний context. Вызов cancel раньше дедлайна освобождает связанные ресурсы и сразу сообщает дочерним операциям, что результат больше не нужен. Обычный шаблон: сразу после успешного создания написать defer cancel(). Даже если функция завершилась быстро или вернула ошибку, cleanup выполнится. Автоматическое наступление deadline не заменяет явный вызов в нормальном раннем пути. CancelFunc можно вызывать повторно, но он не ждёт завершения goroutines: они должны слушать Done и самостоятельно закончить работу.
Ссылки для изучения
Безопасно ли вызывать cancel несколько раз?
Да. CancelFunc можно вызывать несколько раз, в том числе конкурентно; последующие вызовы не меняют состояние. Канал Done закрывается один раз, а Err после отмены стабильно сообщает причину верхнего уровня. Это позволяет нескольким путям завершения использовать один cancel без отдельной защиты sync.Once. Но cancel не закрывает произвольные пользовательские каналы и не ждёт завершения goroutines. Если нужен join, его делают через errgroup, WaitGroup или другой протокол, а workers обязаны реагировать на Done.
Ссылки для изучения
Как передать причину отмены контекста?
context.WithCancelCause возвращает CancelCauseFunc, которому передают содержательную ошибку. context.Cause(ctx) возвращает её для отменённого context и потомков, тогда как ctx.Err() остаётся одной из общих ошибок context.Canceled или context.DeadlineExceeded. Это позволяет отличить «клиент ушёл» от «остановились после ошибки worker», не меняя стандартную проверку отмены. Первая установленная причина сохраняется по правилам распространения родителя и ребёнка; последующий cancel её не перезаписывает. Причина не должна содержать секреты и не заменяет wrapping ошибки на границе операции.
Ссылки для изучения







