Lekcje modułu (5/5)
`context.Context`: anulowanie i limity czasu
Pakiet context jest de facto standardem propagacji **
anulowanie, terminy i wartości związane z zakresem** w całym łańcuchu połączeń,
w wielu gorutynach. Wszystkie standardowe pakiety „sieciowe”.
(net/http, database/sql, os/exec) zaakceptuj context.Context jako
ich pierwszy parametr.
Interfejs
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key any) any
}Done(): kanał zamykany po anulowaniu kontekstu.Err(): powód anulowania (context.Canceledlubcontext.DeadlineExceeded).Deadline(): termin opcjonalny.Value(): wyszukiwanie wartości związanych z zakresem (używaj oszczędnie).
Cztery podstawowe funkcje
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-boundWszystkie formularze pochodne zwracają funkcję cancel: zawsze ją wywołuj
(najlepiej z defer), aby zwolnić zasoby wewnętrzne, nawet jeśli
kontekst już wygasł.
Wzór przekroczenia limitu czasu
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
}Jeżeli queryUser trwa dłużej niż 2 sekundy, ctx.Done() zostaje zamknięty i
funkcja musi przerwać operację.
Przestrzegając kontekstu: wybierz Gotowe()
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
}
}
}Zasada: wszędzie tam, gdzie Twoja funkcja może blokować się przez długi czas, należy to zrobić musi obsłużyć ctx.Done(). W przeciwnym razie kontekst jest „włączany”. nic.
Konwencja pierwszego parametru
func Fetch(ctx context.Context, url string) ([]byte, error) { ... }
// ^^^^^^^^^^^^^^^^^^^
// SEMPRE primo, mai dentro a una struct, mai opzionalectxZAWSZE jako pierwszy parametr o nazwiectx.- Nigdy nie umieszczaj
Contextjako pola struktury (bardzo rzadkie wyjątki). - Nigdy nie przekazuj
nil: użyjcontext.TODO()jako kodu pośredniczącego.
kontekst.WithValue: oszczędnie
type userKey struct{}
ctx := context.WithValue(ctx, userKey{}, currentUser)
// più sotto:
if u, ok := ctx.Value(userKey{}).(*User); ok { ... }Wytyczne:
- TYLKO dla danych o zakresie żądania (identyfikator żądania, identyfikator śledzenia, tożsamość użytkownika).
- NIGDY dla parametrów funkcji: przekazuj je normalnie.
- Klucze niestandardowego, nieeksportowanego typu, aby uniknąć kolizji.
Propagacja wzdłuż łańcucha
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 automatycznie anuluje r.Context(), gdy klient
rozłączy się lub gdy przewodnik powróci. Propagując to wszystkim
wywołania downstream, całe drzewo operacji zostaje anulowane
kaskada: brak niepotrzebnej pracy po rozłączeniu.
Spróbuj
Utwórz kontekst z 1-sekundowym limitem czasu wyprowadzonym z kontekstu.Background() i pamiętaj o wywołaniu cancel z odroczeniem.
Pokaż wskazówkę
KODEF0 zwraca KODEF1; zawsze zadzwoń anuluj.
Rozwiązanie dostępne po 3 próbach
Użyj <-ctx.Done() w zaznaczeniu, aby poczekać na anulowanie kontekstu.
Pokaż wskazówkę
`ctx.Done()` to kanał, który zamyka się, gdy kontekst zostaje anulowany.
Rozwiązanie dostępne po 3 próbach
Zgodnie z konwencją, gdzie w sygnaturze funkcji znajduje się parametr ctx?
func Fetch(???, url string) ([]byte, error)Podsumowanie
context.Contextpropaguje wartości anulowania, terminu i zakresu.Background()/TODO()jako korzeń;WithCancel/WithTimeout/WithDeadlinedo wyprowadzenia.- Zawsze
defer cancel(), aby zwolnić zasoby. - Funkcje „długie” muszą mieć
selectnactx.Done()lub przekazywać ctx do standardowych pakietów. - Konwencja:
ctxjako PIERWSZY parametr, nigdy wewnątrz struktury. Background()0 tylko dla danych o zakresie żądania (identyfikator żądania, identyfikator śledzenia).- W
Background()1,Background()2 jest anulowane w przypadku rozłączenia klienta.