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
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.Canceledoucontext.DeadlineExceeded).Deadline(): délai optionnel.Value(): recherche de valeurs liées à la portée (à utiliser avec parcimonie).
Les quatre fonctions de base
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-boundToutes 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
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()
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
func Fetch(ctx context.Context, url string) ([]byte, error) { ... }
// ^^^^^^^^^^^^^^^^^^^
// SEMPRE primo, mai dentro a una struct, mai opzionalectxTOUJOURS comme premier paramètre, nomméctx.- Ne mettez jamais
Contextcomme champ d'une structure (très rares exceptions). - Ne passez jamais
nil: utilisezcontext.TODO()comme stub.
context.WithValue : avec parcimonie
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
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
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.
Afficher l'indice
`context.WithTimeout(parent, d)` renvoie `(ctx, cancel)` ; appelez toujours pour annuler.
Solution disponible après 3 tentatives
Utilisez <-ctx.Done() dans une sélection pour attendre que le contexte soit annulé.
Afficher l'indice
`ctx.Done()` est un canal qui se ferme lorsque le contexte est annulé.
Solution disponible après 3 tentatives
Par convention, où va le paramètre ctx dans une signature de fonction ?
func Fetch(???, url string) ([]byte, error)Récapitulatif
context.Contextpropage les valeurs d'annulation, de date limite et de portée.Background()/TODO()comme racine ;WithCancel/WithTimeout/WithDeadlinepour dériver.- Toujours
defer cancel()pour libérer les ressources. - Les fonctions "longues" doivent
selectsurctx.Done()ou passer ctx aux packages standards. - Convention :
ctxcomme 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.