Sobes.tech
Middle

Comment sont structurés les contextes dans le langage Go?

sobes.tech IA

Réponse de l'IA

Le contexte (context.Context) en Go est utilisé pour transmettre des informations sur les délais, les annulations et d'autres données entre les limites d'API. Il représente un arbre : chaque contexte est un enfant d'un autre, sauf le racine (context.Background() ou context.TODO()).

Les méthodes principales de l'interface context.Context :

  • Deadline() (deadline time.Time, ok bool): Renvoie la date limite du contexte.
  • Done() <-chan struct{}: Renvoie un canal qui se ferme lors de l'annulation du contexte.
  • Err() error: Renvoie l'erreur qui a causé l'annulation du contexte.
  • Value(key any) any: Renvoie la valeur associée à la clé dans le contexte.

Ils sont créés avec des fonctions du paquet context :

  • context.Background(): Le contexte racine vide, utilisé comme base pour le processus principal.
  • context.TODO(): Utilisé comme marqueur de position lorsque l'on ne sait pas quel contexte utiliser.
  • context.WithCancel(parent Context): Crée un contexte enfant et une fonction d'annulation.
  • context.WithDeadline(parent Context, d time.Time): Crée un contexte enfant avec une date limite.
  • context.WithTimeout(parent Context, timeout time.Duration): Crée un contexte enfant avec un délai d'expiration.
  • context.WithValue(parent Context, key, val any): Crée un contexte enfant avec une valeur.

Principales implémentations de Context :

  • emptyCtx: Basique, non annulable et sans valeurs. Utilise Background et TODO.
  • cancelCtx: Supporte l'annulation. Se compose d'un contexte de base et d'un canal d'annulation.
  • timerCtx: Supporte la date limite/le délai d'expiration. Contient cancelCtx et un temporisateur.
  • valueCtx: Supporte la transmission de valeurs. Contient un contexte de base et une paire clé-valeur.

Lorsqu'un contexte parent est annulé, tous ses enfants le sont automatiquement. Cela permet de propager des signaux d'annulation ou des délais dans la chaîne d'appels.

Exemple d'utilisation de context.WithCancel :

package main

import (
	"context"
	"fmt"
	"time"
)

func main() {
	// Créer le contexte racine et la fonction d'annulation
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel() // Garantit l'annulation à la sortie de main

	go func() {
		select {
		case <-ctx.Done(): // Attendre l'annulation du contexte
			fmt.Println("Tâche annulée :", ctx.Err())
			return
		case <-time.After(5 * time.Second): // Ou terminer après 5 secondes
			fmt.Println("Tâche terminée")
		}
	}()

	// Annuler le contexte depuis un autre endroit
	time.Sleep(1 * time.Second)
	fmt.Println("Annulation du contexte...")
	cancel()

	// Donner du temps au goroutine pour traiter l'annulation
	time.Sleep(100 * time.Millisecond)
}

Exemple d'utilisation de context.WithValue :

package main

import (
	"context"
	"fmt"
)

type userIDKey string

func processRequest(ctx context.Context) {
	if userID, ok := ctx.Value(userIDKey("UserID")).(string); ok {
		fmt.Println("Traitement de la requête pour l'ID utilisateur :", userID)
	} else {
		fmt.Println("ID utilisateur non trouvé dans le contexte")
	}
}

func main() {
	ctx := context.WithValue(context.Background(), userIDKey("UserID"), "12345")
	processRequest(ctx)
}

Les contextes sont sûrs pour la concurrence et immuables, ce qui est important pour le code concurrent. Ils ne sont pas destinés à transmettre des paramètres bruts de fonctions, mais plutôt des métadonnées influant sur l'exécution du processus.