Pakiet Go Context
Większość programistów Go używa context.Context, nie rozumiejąc go w pełni. Można go spotkać w handlerach HTTP, wywołaniach baz danych i metodach SDK. Wielu początkujących przekazuje context.Background() wszędzie.
Ten błąd powoduje problemy. Funkcja Lambda może zawisnąć po przekroczeniu czasu oczekiwania (timeout). Zapytanie do bazy danych może kontynuować działanie po rozłączeniu się użytkownika.
Context pozwala na przesyłanie sygnałów anulowania oraz terminów (deadlines) wewnątrz kodu. Pomaga odpowiedzieć na trzy pytania:
• Czy ta operacja powinna kontynuować działanie? • Kiedy ta operacja musi się zakończyć? • Jakie dane żądania przepływają wraz z tym wywołaniem?
Interfejs Context posiada cztery metody:
Deadline(): Zwraca czas, w którym context zostanie anulowany.Done(): Zwraca kanał, który zostaje zamknięty, gdy context zostanie anulowany. Używaj go w instrukcjachselect, aby przerwać pracę.Err(): Zwraca przyczynę zatrzymania contextu (DeadlineExceededlubCanceled).Value(): Pobiera dane powiązane z żądaniem, takie jak Trace ID.
Context działa jak drzewo. Zaczynasz od kontekstu nadrzędnego (parent) i tworzysz konteksty potomne (children).
Konteksty główne (Root Contexts):
context.Background(): Używaj na początku programu.context.TODO(): Używaj jako tymczasowego znacznika podczas refaktoryzacji.
Konteksty potomne (Child Contexts):
context.WithCancel(): Pozwala na ręczne przerwanie pracy.context.WithTimeout(): Zatrzymuje pracę po określonym czasie.context.WithDeadline(): Zatrzymuje pracę o konkretnej godzinie.context.WithValue(): Przekazuje metadane, takie jak identyfikatory użytkowników (User IDs).
Kluczowa zasada: Zawsze wywołuj funkcję cancel. Użyj defer cancel() natychmiast po utworzeniu kontekstu potomnego. Jeśli o tym zapomnisz, spowodujesz wycieki pamięci.
Dobre praktyki:
- Przekazuj context jako pierwszy argument funkcji.
- Nie przechowuj contextu w strukturach.
- Używaj
context.WithValuewyłącznie do metadanych, a nie do zależności, takich jak klienci baz danych. - Sprawdzaj
ctx.Err()wewnątrz długich pętli, aby móc wcześniej przerwać działanie. - Używaj własnych typów dla kluczy contextu, aby uniknąć kolizji.
Gdy kontekst nadrzędny zostaje anulowany, wszystkie jego konteksty potomne są anulowane automatycznie. Ułatwia to zatrzymanie całego łańcucha operacji w całym systemie.