Context package: cancellation, timeout, values
- ⬜🔀 Goroutines e channels: concurrency model(Go Profissional)
Recomendamos completar os pré-requisitos antes de seguir, mas nada te impede de continuar.
Por que context existe
Request distribuída precisa de três coisas: cancelamento propagado ("o cliente desistiu, pare"), deadline absoluto ("cut em 500 ms") e valores request-scoped (trace-id). context.Context é a estrutura canônica para carregar os três por toda a stack — handler, service, repository, driver.
Construtores e lifecycle
| Construtor | Quando o cancelamento dispara | Erro devolvido | Uso típico |
|---|---|---|---|
| Raiz | Nunca — é o ponto de partida | — | Início do programa e testes |
| Com cancelamento manual | Quando alguém chama a função de cancelar | Cancelado | Encerrar trabalho em segundo plano ao sair de um escopo |
| Com prazo absoluto | Ao chegar o instante marcado | Prazo excedido | Fim de janela conhecido — encerrar antes do limite do servidor |
| Com duração | Depois do tempo decorrido | Prazo excedido | Chamada externa que não pode demorar mais que N segundos |
| Com valor | Herda do pai | do pai | Somente dado de escopo de requisição — nunca dependência |
// Base
ctx := context.Background() // root (main, test)
ctx = context.TODO() // placeholder em refactor
// Cancelamento manual
ctx, cancel := context.WithCancel(parent)
defer cancel()
// Deadline absoluto
ctx, cancel := context.WithDeadline(parent, time.Now().Add(500*time.Millisecond))
defer cancel()
// Timeout relativo (atalho para WithDeadline)
ctx, cancel := context.WithTimeout(parent, 500*time.Millisecond)
defer cancel()
// Values (request-id, trace-id, user autenticado — só isso)
type ctxKey string
const userKey ctxKey = "user"
ctx = context.WithValue(ctx, userKey, user)
u, _ := ctx.Value(userKey).(User)Propagação correta
func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() // herda cancel/deadline do servidor
u, err := h.svc.Find(ctx, id) // passa adiante
if err != nil {
if errors.Is(err, context.Canceled) { return }
http.Error(w, err.Error(), 500); return
}
json.NewEncoder(w).Encode(u)
}
func (s *Service) Find(ctx context.Context, id string) (User, error) {
return s.repo.Get(ctx, id) // até o driver
}
func (r *Repo) Get(ctx context.Context, id string) (User, error) {
// database/sql, redis e HTTP aceitam ctx
return r.db.QueryRowContext(ctx, "select ..."), nil
}Toda lib séria (database/sql, net/http, grpc-go, redis clients) tem variante Context das operações. Usar as não-Context é sinônimo de ignorar cancelamento.
Observando ctx.Done
func work(ctx context.Context, ch <-chan Job) error {
for {
select {
case <-ctx.Done():
return ctx.Err() // Canceled ou DeadlineExceeded
case j, ok := <-ch:
if !ok { return nil }
process(ctx, j)
}
}
}O cliente fecha a conexão HTTP no meio de uma consulta pesada. O que faz a consulta parar de fato?
Goroutine leak por ctx esquecido
O padrão mais comum de leak em Go: goroutine que não escuta ctx.Done e fica esperando um channel que ninguém mais alimenta. Resultado: métrica go_goroutines sobe monotonicamente até OOM. Cheque sempre com pprof goroutine profile.
Quando usar WithValue
Só para request-scoped data (request-id, trace-id, user autenticado por middleware). Nunca para logger, repository ou config — esses vão por struct injetada. Se começar a usar WithValue para tudo, você reinventou service locator; teste fica pesado.
Resumo operacional
ctx primeiro arg, defer cancel sempre, propagação obrigatória até o driver, errors.Is(err, context.Canceled) para não gritar em log quando é cancelamento saudável. Disciplina simples, ganho enorme em estabilidade.
Perguntas frequentes
❓ Para que serve o contexto em Go?
❓ Onde o contexto deve aparecer?
❓ Valores no contexto são boa prática?
Fixando
Qual é a origem mais comum de vazamento de goroutine descrita no módulo?
Por que o módulo restringe o carregamento de valores no contexto a dados de escopo de requisição?
Terminou de ler?
Marcar como concluído registra o XP, mantém sua sequência e coloca 3 cartas deste módulo na fila de revisão espaçada.
Próximos passos sugeridos
Temas deste módulo
Discussão
Carregando comentários…