Пакет context — стандарт для управления временем жизни (cancellation, timeout) и передачи метаданных между частями кода, особенно при работе с goroutine и внешними вызовами (HTTP, DB).
Создание:
Завершать контекст важно для корректного освобождения ресурсов. Пример:
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() // далее ctx используется в goroutine/HTTP запросе
Типовой паттерн — передавать context первым аргументом функций, пример:
func process(ctx context.Context) error { ... }
Когда можно передавать context.TODO() и context.Background() вместо реального context, и в чём разница между ними?
Многие используют context.Background() как placeholder. Но:
context.Background() — корень дерева, используйте только в main() и тестах, при инициализации самого "дерева контекстов".context.TODO() нужен, если пока не ясно, какой должен быть контекст — для временного "затыкания дыр" при рефакторинге. В production коде TODO неприемлем: нужно точно знать, что и куда передаётся.История
В микросервисе забыли вызвать cancel() после создания context.WithTimeout() — запросы стопорились, завершённые goroutine оставляли "висящие" таймеры в рантайме, что приводило к утечке памяти.
История
Передача context.Background() вместо пришедшего из запроса context в handler'ах теряла всю цепочку cancellation и trace-id, отчего ограничения таймаутов не работали, отмены запросов не срабатывали.
История
Через context.WithValue() разработчики передавали данные, но ключи были строками. В результате, из-за возможных коллизий ключей из разных пакетов, возникали неожиданные ошибки ("ключ уже занят"). Правильная практика: использовать уникальные типы для ключей.