context.Context: Cancelamento como API de Primeira Classe
context.Context é como os serviços Go param o trabalho cooperativamente quando um cliente sai, um deadline expira ou um processo é encerrado.
Busque em todas as páginas da documentação
context.Context é como os serviços Go param o trabalho cooperativamente quando um cliente sai, um deadline expira ou um processo é encerrado.
Não é um açúcar opcional em código de servidor - é o contrato padrão para timeouts, cancelamento e metadados com escopo de requisição em manipuladores HTTP, chamadas de banco de dados, gRPC e workers em segundo plano.
Noções básicas de context reúne snippets executáveis; artigos irmãos cobrem propagação HTTP, deadlines entre serviços, valores, integração com banco de dados/gRPC, testes e convenções de equipe.
context.Context é um handle imutável passado por pilhas de chamadas. Ele sinaliza quando o trabalho deve parar e carrega um pequeno conjunto de valores com escopo de requisição.force-kill em vez de um esvaziamento gracioso.sleep em um caminho de requisição ou job deve aceitar ctx context.Context como seu primeiro parâmetro.database/sql, errgroup, desligamento gracioso, logging estruturado com IDs de requisição.Imagine uma requisição entrando no seu serviço como uma árvore de chamadas de função.
Na raiz, algo cria um contexto - http.Request.Context() para HTTP, context.Background() para inicialização de processo, ou context.WithTimeout para um job com limite de tempo.
Cada chamada downstream recebe esse contexto (ou um filho derivado dele).
Quando a raiz é cancelada - desconexão do cliente, timeout ou cancel() explícito - todos os descendentes que respeitam ctx.Done() devem parar prontamente.
Um contexto carrega três preocupações:
Done() fecha quando o trabalho deve terminar.Deadline().Contextos formam uma cadeia pai-filho.
context.WithCancel(parent) retorna um filho e uma função cancel.
Chamar cancel() no filho não cancela o pai, mas cancelar o pai cancela todos os descendentes.
Essa propagação unidirecional é deliberada: o upstream é dono do ciclo de vida.
A assinatura idiomática da função é:
func FetchUser(ctx context.Context, id string) (*User, error)Chamadores passam ctx inalterado ou o envolvem:
ctx, cancel := context.WithTimeout(parent, 2*time.Second)
defer cancel()Código bloqueante deve usar select em ctx.Done() ou usar APIs que aceitam contexto (db.QueryContext, stubs gRPC, http.NewRequestWithContext).
Quando ctx termina, retorne ctx.Err() - geralmente context.Canceled ou context.DeadlineExceeded.
Servidores HTTP conectam isso automaticamente.
net/http dá a cada requisição r.Context(), que cancela quando o cliente fecha a conexão ou o servidor atinge os limites ReadHeaderTimeout/WriteTimeout.
Frameworks como chi, gin e echo expõem o mesmo contexto de requisição através de suas APIs de manipulador.
google.golang.org/grpc propaga metadados e deadlines através de context.Context em cada RPC.
database/sql métodos que terminam em Context honram o cancelamento no nível do driver quando suportado.
Caminhos de desligamento derivam um contexto de timeout de context.Background():
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
srv.Shutdown(ctx)| Mecanismo | O que sinaliza | Fonte Típica |
|---|---|---|
WithCancel | Parada manual | Saída do manipulador, falha de errgroup |
WithTimeout | Orçamento relativo | Chamada de cliente por RPC |
WithDeadline | Tempo final absoluto | Cabeçalho grpc-timeout upstream |
Request.Context() | Desconexão do cliente | net/http |
context.WithoutCancel | Desanexar para limpeza | Logging pós-resposta (Go 1.21+) |
Serviços de produção empilham deadlines em cada salto.
Um gateway de borda pode permitir 5s; um serviço interno recebe 3s após a sobrecarga do middleware; uma consulta de banco de dados recebe 500ms.
Cada camada deve definir um deadline menor que seu pai para que haja margem para serialização e retentativas.
controller-runtime reconciliadores usam contexto para parar o trabalho quando um gerenciador é encerrado ou um lease é perdido.
Controladores gerados por kubebuilder passam ctx para chamadas de cliente para que os watches do servidor de API respeitem o cancelamento.
golangci-lint inclui verificações (via staticcheck e linters customizados) para uso indevido de contexto - passar context.Background() dentro de manipuladores, armazenar contexto em structs ou ignorar ctx em loops.
Para valores, a equipe Go recomenda tipos de chave não exportados para evitar colisões:
type ctxKey int
const requestIDKey ctxKey = 1Nunca use valores de contexto para parâmetros opcionais que pertencem aos argumentos da função.
Combine contexto com observabilidade: extraia IDs de requisição do contexto no middleware e anexe-os a logs estruturados e traces.
| Abordagem | Força | Fraqueza | Melhor Encaixe |
|---|---|---|---|
| Cancelamento de Contexto | Padrão, composível | Requer disciplina em cada chamada | Pilhas HTTP/gRPC/DB |
time.After por chamada | Timeout local simples | Sem propagação para filhos | Scripts de goroutine única |
Canal done manual | Ciclo de vida customizado | Reinventa o contexto | Caminhos de código legados |
| Apenas sinais de processo | Parada em nível de SO | Sem granularidade por requisição | Ferramentas CLI |
errgroup + contexto | Cancela irmãos em caso de erro | Necessita de configuração explícita do grupo | Fan-out paralelo |
r.Context().cancel() de um filho para os descendentes, não os ancestrais.Convenção da comunidade e ferramentas gofmt/review esperam ctx context.Context primeiro.
Mantém o sinal visível em cada local de chamada.
WithCancel para quando você chama cancel() ou quando o pai termina.
WithTimeout também define um deadline e chama cancel automaticamente quando o tempo expira.
Sim para WithCancel, WithTimeout e WithDeadline.
cancel() adiado libera recursos do timer mesmo que o deadline tenha passado cedo.
Retorne ctx.Err() inalterado quando o cancelamento causou a falha.
Envolva com %w apenas se os chamadores precisarem de contexto extra, preservando errors.Is.
Métodos como QueryContext passam o cancelamento para o driver quando suportado.
Sempre prefira variantes *Context a chamadas bloqueantes sem contexto.
Deadlines e metadados viajam em context.Context.
Stubs de cliente derivam timeouts do contexto; servidores os leem para impor.
Nunca - use context.Background() ou context.TODO() apenas nas raízes.
Bibliotecas devem documentar que nil causa pânico ou é rejeitado.
Um placeholder quando o contexto pai correto não está claro durante refatorações.
Substitua por um pai real antes de enviar.
Use tipos de chave customizados não exportados em cada pacote.
Chaves de string são um risco de colisão em grandes bases de código.
Não - errgroup usa contexto para cancelar goroutines irmãs na primeira falha.
Eles se complementam.
Versões do Stack: Esta página foi escrita para Go 1.26.x (padrão GC Green Tea, go fix modernizers - verifique o patch na compilação), chi (mais recente - verifique na compilação), gin (mais recente - verifique na compilação), echo (mais recente - verifique na compilação), google.golang.org/grpc (mais recente - verifique na compilação), sigs.k8s.io/controller-runtime (mais recente - verifique na compilação), kubebuilder (mais recente - verifique na compilação), tinygo (mais recente - verifique na compilação), wazero (mais recente - verifique na compilação), e golangci-lint (mais recente - verifique o conjunto de linters na compilação).
Revisado por Chris St. John·Última atualização: 19 de jul. de 2026