Das Paket context ist der Standard zur Verwaltung der Lebensdauer (Abbruch, Timeout) und zur Übertragung von Metadaten zwischen Teilen des Codes, insbesondere bei der Arbeit mit Goroutines und externen Aufrufen (HTTP, DB).
Erstellung:
Es ist wichtig, den Kontext zu beenden, um Ressourcen korrekt freizugeben. Beispiel:
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() // anschließend wird ctx in Goroutine/HTTP-Anfrage verwendet
Das typische Muster ist, den Kontext als ersten Parameter in Funktionen zu übergeben, Beispiel:
func process(ctx context.Context) error { ... }
Wann kann man context.TODO() und context.Background() anstelle des tatsächlichen Kontextes übergeben, und was ist der Unterschied zwischen ihnen?
Viele verwenden context.Background() als Platzhalter. Aber:
context.Background() ist der Wurzelknoten des Baums, verwenden Sie es nur in main() und Tests, bei der Initialisierung des "Baums der Kontexte".context.TODO() wird benötigt, wenn noch nicht klar ist, welcher Kontext benötigt wird — zum vorübergehenden "Stopfen von Löchern" während der Refaktorisierung. Im Produktionscode ist TODO unakzeptabel: man muss genau wissen, was und wo übergeben wird.Geschichte
In einem Mikrodienst wurde vergessen, cancel() nach der Erstellung von context.WithTimeout() aufzurufen — Anfragen verhakten sich, abgeschlossene Goroutines ließen "hängende" Timer zur Laufzeit zurück, was zu Speicherlecks führte.
Geschichte
Die Übergabe von context.Background() anstelle des aus der Anfrage kommenden Kontextes in Handlers verlor die gesamte Kette der Abbrüche und der trace-id, wodurch die Timeout-Beschränkungen nicht funktionierten und die Abbrüche der Anfragen nicht wirksam wurden.
Geschichte
Durch context.WithValue() übermittelten Entwickler Daten, aber die Schlüssel waren Strings. Infolgedessen führten mögliche Schlüsselkolisionen aus verschiedenen Paketen zu unerwarteten Fehlern ("Schlüssel bereits belegt"). Die richtige Praxis: einzigartige Typen für Schlüssel verwenden.