No Go você não mata uma goroutine de fora. Você avisa que ela deve parar, e ela escolhe sair. O context é o canal desse aviso: ele desce do request por toda a árvore de chamadas, e um cancelamento no topo derruba a subárvore inteira. Crie filhos aqui embaixo, cancele o pai, e veja a propagação.
A raiz é o context do request. Clique em "criar filhos" pra abrir goroutines filhas, depois "cancelar pai" e veja o que acontece em cada modo.
ativa (rodando, ouvindo Done())cancelada (saiu limpo)vazada (continua rodando à toa)
Cancelamento no Go é cooperativo. O runtime não preempta nem mata a goroutine: ela precisa escutar ctx.Done() e retornar por conta própria. Se ela não escuta e fica bloqueada, vira leak. O context flui do topo (o request HTTP) pra baixo, sempre como primeiro argumento, e um cancel ou timeout lá em cima libera todo mundo.
WithCancel: aviso manual
ctx, cancel := context.WithCancel(parent)
defercancel() // sempre libere o contextgoworker(ctx)
// ... quando desistir:cancel() // fecha ctx.Done() pra toda a subárvore
funcworker(ctx context.Context) {
for {
select {
case <-ctx.Done():
return// avisado: sai limpocase job := <-jobs:
handle(job)
}
}
}
🧠 Desafio — Context & Cancel
Brinca com criar filhos, cancelar e o timeout (nos dois modos) antes de responder. As duas últimas são de reflexão: escreve a sua e só então revela o modelo.