Conceptos básicos de context
10 ejemplos para empezar con el paquete context: 7 básicos y 3 intermedios.
Busca en todas las páginas de la documentación
10 ejemplos para empezar con el paquete context: 7 básicos y 3 intermedios.
mkdir ctxdemo && cd ctxdemo && go mod init example.com/ctxdemo.main.go (o archivos separados en un mismo paquete) y ejecútalo con go run ..Los contextos raíz inician cadenas que no tienen cancelación de padre.
package main
import (
"context"
"fmt"
)
func main() {
fmt.Println(context.Background().Err() == nil)
fmt.Println(context.TODO().Err() == nil)
}context.Background() es el contexto vacío de nivel superior para main, servidores y pruebas.context.TODO() es un marcador de posición durante refactorizaciones cuando el padre aún no está conectado.Relacionado: context.Context: Cancelación como API de primera clase - por qué existe context
La cancelación manual detiene el trabajo descendiente.
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
<-ctx.Done()
fmt.Println("detenido:", ctx.Err())
}()
time.Sleep(50 * time.Millisecond)
cancel()
time.Sleep(20 * time.Millisecond)
}WithCancel devuelve un contexto hijo y una función cancel.defer cancel() para liberar recursos, incluso si cancelas anticipadamente.ctx.Err() devuelve context.Canceled después de una cancelación manual.Relacionado: Propagación de cancelación en manejadores HTTP - ciclos de vida de solicitudes reales
Un plazo relativo cancela automáticamente.
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
select {
case <-time.After(250 * time.Millisecond):
fmt.Println("trabajo finalizado")
case <-ctx.Done():
fmt.Println("tiempo agotado:", ctx.Err())
}
}WithTimeout(parent, d) es un atajo para WithDeadline(parent, time.Now().Add(d)).Done() se cierra y Err() es context.DeadlineExceeded.Relacionado: Plazos y tiempos de espera a través de los límites del servicio - presupuestos de servicio
Los tiempos de finalización absolutos del reloj de pared se adaptan a la caducidad proporcionada por el upstream.
package main
import (
"context"
"fmt"
"time"
)
func main() {
deadline := time.Now().Add(80 * time.Millisecond)
ctx, cancel := context.WithDeadline(context.Background(), deadline)
defer cancel()
if d, ok := ctx.Deadline(); ok {
fmt.Println("plazo:", d.Format(time.RFC3339))
}
<-ctx.Done()
fmt.Println(ctx.Err())
}Deadline() informa el punto de corte y si se ha establecido un plazo.WithTimeout cuando piensas en duraciones; usa WithDeadline al sincronizar con una marca de tiempo externa.Relacionado: Plazos y tiempos de espera a través de los límites del servicio - propagación de la caducidad
El trabajo prolongado debe sondear la cancelación entre iteraciones.
package main
import (
"context"
"fmt"
"time"
)
func work(ctx context.Context) error {
for i := 0; i < 10; i++ {
select {
case <-ctx.Done():
return ctx.Err()
default:
time.Sleep(30 * time.Millisecond)
fmt.Println("tick", i)
}
}
return nil
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
fmt.Println(work(ctx))
}select con default evita el bloqueo cuando ctx aún está activo.ctx.Err() para que los llamadores distingan la cancelación de otros fallos.ctx en lugar de sondeos manuales cuando estén disponibles.Relacionado: Probar código que acepta context.Context - afirmando rutas de cancelación
La forma estándar de la función propaga el ciclo de vida hacia abajo en la pila.
package main
import (
"context"
"fmt"
)
func fetch(ctx context.Context, id int) (string, error) {
if err := ctx.Err(); err != nil {
return "", err
}
return fmt.Sprintf("user-%d", id), nil
}
func handler(ctx context.Context) error {
name, err := fetch(ctx, 42)
if err != nil {
return err
}
fmt.Println(name)
return nil
}
func main() {
_ = handler(context.Background())
}ctx y colócalo primero: los revisores y los linters esperan esto.ctx.Err() antes de un trabajo costoso cuando las llamadas son profundas.ctx hacia abajo; no crees un Background() nuevo a mitad de la solicitud.Relacionado: Mejores prácticas del paquete context - reglas de nomenclatura del equipo
Las claves tipadas transportan datos transversales con moderación.
package main
import (
"context"
"fmt"
)
type ctxKey string
const requestIDKey ctxKey = "requestID"
func withRequestID(ctx context.Context, id string) context.Context {
return context.WithValue(ctx, requestIDKey, id)
}
func requestID(ctx context.Context) string {
v, _ := ctx.Value(requestIDKey).(string)
return v
}
func main() {
ctx := withRequestID(context.Background(), "req-abc")
fmt.Println(requestID(ctx))
}Relacionado: Valores de context: Cuándo y cuándo no - disciplina de valores
La cancelación fluye solo del padre al hijo.
package main
import (
"context"
"fmt"
)
func main() {
parent, parentCancel := context.WithCancel(context.Background())
defer parentCancel()
child, childCancel := context.WithCancel(parent)
defer childCancel()
childCancel()
fmt.Println("error del padre:", parent.Err())
fmt.Println("error del hijo:", child.Err())
}childCancel() establece child.Err() en context.Canceled.parentCancel().Relacionado: Antipatrones de uso incorrecto de context - errores de ciclo de vida
Cada capa debe restar la sobrecarga del presupuesto restante.
package main
import (
"context"
"fmt"
"time"
)
func callDownstream(parent context.Context) error {
ctx, cancel := context.WithTimeout(parent, 50*time.Millisecond)
defer cancel()
select {
case <-time.After(200 * time.Millisecond):
return nil
case <-ctx.Done():
return ctx.Err()
}
}
func main() {
parent, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
fmt.Println(callDownstream(parent))
}DeadlineExceeded en la capa que estableció el tiempo de espera más corto para facilitar la depuración.Relacionado: Plazos y tiempos de espera a través de los límites del servicio - presupuestos de salto
Adjunta una razón a la cancelación para obtener errores más claros.
package main
import (
"context"
"errors"
"fmt"
)
func main() {
ctx, cancel := context.WithCancelCause(context.Background())
defer cancel(nil)
cause := errors.New("el fallo de validación upstream")
cancel(cause)
fmt.Println(context.Cause(ctx))
}WithCancelCause se empareja con context.Cause(ctx) para la observabilidad.ctx.Err() en los límites de la API a menos que los llamadores necesiten la causa.Relacionado: Probar código que acepta context.Context - afirmando causas de cancelación
Versiones de la pila: Esta página se escribió para Go 1.26.x (GC predeterminado de Green Tea, go fix modernizers - verifica el parche en la compilación), chi (última versión - verifica en la compilación), gin (última versión - verifica en la compilación), echo (última versión - verifica en la compilación), google.golang.org/grpc (última versión - verifica en la compilación), sigs.k8s.io/controller-runtime (última versión - verifica en la compilación), kubebuilder (última versión - verifica en la compilación), tinygo (última versión - verifica los objetivos de la placa en la compilación), wazero (última versión - verifica en la compilación) y golangci-lint (última versión - verifica el conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 18 jul 2026