Saltar al contenido principal
eLearner.app
Módulo 7 · Lección 5 de 535/50 en el curso~14 min
Lecciones del módulo (5/5)

context.Context: cancelación y plazos

El paquete context es el estándar de facto para propagar cancelación, plazos y valores de alcance a lo largo de la cadena de llamadas, a través de múltiples gorutinas. Todos los paquetes estándar de "redes" (net/http, database/sql, os/exec) aceptan un context.Context como su primer parámetro.

La interfaz

Go
type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key any) any
}
  • Done(): canal que se cierra cuando se cancela el contexto.
  • Err(): motivo de cancelación (context.Canceled o context.DeadlineExceeded).
  • Deadline(): plazo opcional.
  • Value(): búsqueda de valores de ámbito limitado (úselo con moderación).

Las cuatro funciones básicas

Go
ctx := context.Background()              // radice: usalo in main, init, test
ctx := context.TODO()                    // "non so ancora": stub esplicito

ctx, cancel := context.WithCancel(parent)               // cancel manuale
ctx, cancel := context.WithTimeout(parent, d)           // scadenza relativa
ctx, cancel := context.WithDeadline(parent, t)          // scadenza assoluta

ctx := context.WithValue(parent, key, value)            // valore scope-bound

Todas las formas derivadas devuelven una función cancel: llámala siempre (idealmente con defer) para liberar recursos internos, incluso si el El contexto ya ha expirado.

Patrón de tiempo de espera

Go
func fetchUser(id string) (*User, error) {
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()

    return queryUser(ctx, id)   // queryUser deve rispettare ctx
}

Si queryUser tarda más de 2 segundos, ctx.Done() se cierra y la función debe abortar la operación.

Respetando el contexto: seleccione en Listo()

Go
func slowWork(ctx context.Context) error {
    for {
        select {
        case <-ctx.Done():
            return ctx.Err()      // canceled o deadline exceeded
        case <-time.After(100 * time.Millisecond):
            // un tick di lavoro
        }
    }
}

La regla: en cualquier lugar donde su función pueda bloquearse durante mucho tiempo, debe manejar ctx.Done(). De lo contrario, el contexto está "encendido" durante nada.

Convención de primer parámetro

Go
func Fetch(ctx context.Context, url string) ([]byte, error) { ... }
//        ^^^^^^^^^^^^^^^^^^^
// SEMPRE primo, mai dentro a una struct, mai opzionale
  • ctx SIEMPRE como primer parámetro, denominado ctx.
  • Nunca ponga Context como campo de una estructura (excepciones muy raras).
  • Nunca pase nil: use context.TODO() como código auxiliar.

contexto.WithValue: con moderación

Go
type userKey struct{}

ctx := context.WithValue(ctx, userKey{}, currentUser)
// più sotto:
if u, ok := ctx.Value(userKey{}).(*User); ok { ... }

Pautas:

  • SÓLO para datos con alcance de solicitud (ID de solicitud, ID de seguimiento, identidad de usuario).
  • NUNCA para parámetros de función: páselos normalmente.
  • Claves de tipo personalizado no exportado para evitar colisiones.

Propagación a lo largo de la cadena.

Go
func handleHTTP(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context()   // context legato al ciclo di vita della richiesta
    user, err := fetchUser(ctx, r.URL.Query().Get("id"))
    if err != nil { ... }
    // ...
}

net/http cancela automáticamente r.Context() cuando el cliente se desconecta o cuando el controlador regresa. Al propagarlo a todos llamadas posteriores, todo el árbol de operaciones se cancela en cascada: no se desperdicia trabajo después de la desconexión.

Pruébalo

Ejercicio#go.m7.l5.e1
Intentos: 0Cargando...

Cree un contexto con un tiempo de espera de 1 segundo derivado de context.Background() y recuerde llamar a cancelar con aplazamiento.

Cargando editor...
Mostrar pista

CÓDIGOF0 devuelve CÓDIGO1; siempre llame a cancelar.

Solución disponible después de 3 intentos

Ejercicio#go.m7.l5.e2
Intentos: 0Cargando...

Utilice <-ctx.Done() en una selección para esperar a que se cancele el contexto.

Cargando editor...
Mostrar pista

`ctx.Done()` es un canal que se cierra cuando se cancela el contexto.

Solución disponible después de 3 intentos

Cuestionario#go.m7.l5.e3
Listo

Por convención, ¿dónde va el parámetro ctx en la firma de una función?

Go
func Fetch(???, url string) ([]byte, error)
Opciones de respuesta

Resumen

  • context.Context propaga valores de cancelación, fecha límite y alcance limitado.
  • Background()/TODO() como raíz; WithCancel/WithTimeout/WithDeadline para derivar.
  • Siempre defer cancel() para liberar recursos.
  • Las funciones "largas" deben select en ctx.Done() o pasar ctx a paquetes estándar.
  • Convención: ctx como PRIMER parámetro, nunca dentro de una estructura.
  • Background()0 solo para datos de ámbito de solicitud (ID de solicitud, ID de seguimiento).
  • En Background()1, Background()2 se cancela al desconectarse el cliente.