Pakiet context to standard do zarządzania cyklem życia (anulowanie, timeout) oraz przekazywania metadanych między częścią kodu, szczególnie przy pracy z goroutine i zewnętrznymi wywołaniami (HTTP, DB).
Tworzenie:
Kończenie kontekstu jest ważne dla poprawnego uwolnienia zasobów. Przykład:
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() // dalej ctx jest używane w goroutine/żądaniu HTTP
Typowy wzorzec — przekazywanie kontekstu jako pierwszego argumentu funkcji, przykład:
func process(ctx context.Context) error { ... }
Kiedy można przekazywać context.TODO() i context.Background() zamiast rzeczywistego kontekstu, i jaka jest różnica między nimi?
Wielu używa context.Background() jako placeholder. Jednak:
context.Background() — korzeń drzewa, używaj tylko w main() i testach, podczas inicjalizacji samego "drzewa kontekstów".context.TODO() jest potrzebny, gdy nie jest jeszcze jasne, jaki powinien być kontekst — do tymczasowego "zakrywania dziur" podczas refaktoryzacji. W kodzie produkcyjnym TODO jest nieakceptowalne: trzeba dokładnie wiedzieć, co i gdzie jest przekazywane.Historia
W mikrousłudze zapomniano wywołać cancel() po stworzeniu context.WithTimeout() — zapytania stawały w miejscu, zakończone goroutine zostawiały "wiszące" timery w runtime, co prowadziło do wycieków pamięci.
Historia
Przekazywanie context.Background() zamiast przychodzącego z żądania kontekstu w handlerach traciło całą sieć anulowania i trace-id, przez co ograniczenia timeout nie działały, anulowanie zapytań nie zachodziło.
Historia
Poprzez context.WithValue() deweloperzy przekazywali dane, ale klucze były stringami. W rezultacie, z powodu możliwych kolizji kluczy z różnych pakietów, występowały nieoczekiwane błędy ("klucz już zajęty"). Poprawna praktyka: używać unikalnych typów dla kluczy.