Passer au contenu principal
eLearner.app
Module 7 · Leçon 5 sur 535/50 dans le cours~14 min
Leçons du module (5/5)

context.Context : annulation et délais

Le package context est le standard de facto pour la propagation annulation, délais et valeurs liées au périmètre tout au long de la chaîne d'appel, sur plusieurs goroutines. Tous les forfaits "réseau" standards (net/http, database/sql, os/exec) acceptent un context.Context comme leur premier paramètre.

L'interface

Go
type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key any) any
}
  • Done() : canal qui se ferme lorsque le contexte est annulé.
  • Err() : motif d'annulation (context.Canceled ou context.DeadlineExceeded).
  • Deadline() : délai optionnel.
  • Value() : recherche de valeurs liées à la portée (à utiliser avec parcimonie).

Les quatre fonctions de base

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

Toutes les formes dérivées renvoient une fonction cancel : appelez-la toujours (idéalement avec defer) pour libérer des ressources internes, même si le le contexte a déjà expiré.

Modèle de délai d'attente

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 prend plus de 2 secondes, ctx.Done() est fermé et la fonction doit abandonner l'opération.

Respect du contexte : sélectionnez sur Done()

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 règle : partout où votre fonction risque de bloquer pendant une longue période, elle doit gérer ctx.Done(). Sinon, le contexte est "activé" pour rien.

Convention du premier paramètre

Go
func Fetch(ctx context.Context, url string) ([]byte, error) { ... }
//        ^^^^^^^^^^^^^^^^^^^
// SEMPRE primo, mai dentro a una struct, mai opzionale
  • ctx TOUJOURS comme premier paramètre, nommé ctx.
  • Ne mettez jamais Context comme champ d'une structure (très rares exceptions).
  • Ne passez jamais nil : utilisez context.TODO() comme stub.

context.WithValue : avec parcimonie

Go
type userKey struct{}

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

Lignes directrices :

  • UNIQUEMENT pour les données de portée de demande (ID de demande, ID de trace, identité de l'utilisateur).
  • JAMAIS pour les paramètres de fonction : passez-les normalement.
  • Clés de type personnalisées non exportées pour éviter les collisions.

Propagation le long de la chaîne

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 annule automatiquement r.Context() lorsque le client se déconnecte ou lorsque le gestionnaire revient. En le propageant à tous appels en aval, l'ensemble de l'arborescence des opérations est annulée dans cascade : pas de travail inutile après la déconnexion.

Essayez-le

Exercice#go.m7.l5.e1
Tentatives : 0Chargement…

Créez un contexte avec un délai d'attente d'une seconde dérivé de context.Background() et n'oubliez pas d'appeler Cancel avec defer.

Chargement de l'éditeur…
Afficher l'indice

`context.WithTimeout(parent, d)` renvoie `(ctx, cancel)` ; appelez toujours pour annuler.

Solution disponible après 3 tentatives

Exercice#go.m7.l5.e2
Tentatives : 0Chargement…

Utilisez <-ctx.Done() dans une sélection pour attendre que le contexte soit annulé.

Chargement de l'éditeur…
Afficher l'indice

`ctx.Done()` est un canal qui se ferme lorsque le contexte est annulé.

Solution disponible après 3 tentatives

Quiz#go.m7.l5.e3
Prêt

Par convention, où va le paramètre ctx dans une signature de fonction ?

Go
func Fetch(???, url string) ([]byte, error)
Options de réponse

Récapitulatif

  • context.Context propage les valeurs d'annulation, de date limite et de portée.
  • Background()/TODO() comme racine ; WithCancel/WithTimeout/WithDeadline pour dériver.
  • Toujours defer cancel() pour libérer les ressources.
  • Les fonctions "longues" doivent select sur ctx.Done() ou passer ctx aux packages standards.
  • Convention : ctx comme PREMIER paramètre, jamais dans une struct.
  • Background()0 uniquement pour les données à l'échelle de la demande (ID de demande, ID de trace).
  • Dans Background()1, Background()2 est annulé à la déconnexion du client.