ТопикиТопик 04
Управление контекстом
О чём этот блок
context.Context — это стандартный язык отмены и дедлайнов в Go. Любой
сетевой вызов, любой обработчик HTTP-запроса, любая фоновая задача должны уметь
быть отменёнными: по таймауту, по сигналу shutdown или потому что результат
уже не нужен. Этот блок строит навык, который отделяет учебный код от
продового: распространение отмены через границы вызовов и завершение работы
без зависших горутин и протекающих ресурсов.
Контекст образует дерево: отмена родителя отменяет всех потомков. ctx.Done()
— это тот же закрытый канал как broadcast из первого блока, только обёрнутый в
общепринятый интерфейс. Понимание этой связи делает контекст не «магией из
стандартной библиотеки», а естественным продолжением каналов и select.
Что вы научитесь делать
- Накладывать жёсткий таймаут поверх внешнего
ctxчерезcontext.WithTimeoutи всегда вызыватьcancel(). - Запускать набор фоновых задач от одного контекста и корректно завершать их
все по
ctx.Done()(graceful shutdown). - Реализовывать паттерн «первый успешный ответ»: разослать запрос по репликам, взять первый успех и отменить остальные.
- Связывать таймауты, родительскую отмену и сигнал завершения в одно дерево отмены.
- Не допускать утечек горутин при отмене — каждая запущенная горутина обязана уметь выйти.
Карта задач
- 13 · HTTP-запрос с жёстким таймаутом — производный контекст с таймаутом
200ms поверх входного
ctx; обязательныйdefer cancel(); передачаctxвhttp.Request. - 14 · Древовидная отмена (Graceful Shutdown) — один
ctxна несколько фоновых задач; каждая слушаетctx.Done(); завершение всего набора без зависаний. - 15 · First Successful (быстрый ответ) — параллельные запросы к репликам;
первый успех отменяет остальных через
ctx; возврат самого быстрого результата.
Связанные главы учебника
- context — дерево отмены,
Done(), таймауты, передача контекста через границы вызовов. - Утечки горутин и гонки — как отмена предотвращает goroutine leak и как такие утечки находить.
// Идиома блока: жёсткий таймаут поверх внешнего контекста.
ctx, cancel := context.WithTimeout(parent, 200*time.Millisecond)
defer cancel() // освобождает ресурсы, даже если успели вовремя