context.WithCancel создаёт контекст, который можно отменить вручную:
ctx, cancel := context.WithCancel(context.Background())
defer cancel() // всегда вызывай cancel чтобы не утекли ресурсы
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("cancelled:", ctx.Err()) // context canceled
return
case <-time.After(1 * time.Second):
fmt.Println("working...")
}
}
}(ctx)
time.Sleep(3 * time.Second)
cancel() // отменяем — горутина завершится
Отмена каскадная: если отменить родительский контекст, все дочерние тоже отменятся.
parent, cancelParent := context.WithCancel(ctx)
child, cancelChild := context.WithCancel(parent)
cancelParent() // child тоже отменён
Паттерн: передавай ctx первым аргументом во все функции, которые могут работать долго или делать I/O.