Salt la conținutul principal
Modulul 7 · Lecția 5 din 535/50 în curs~14 min
Lecții din modul (5/5)

`context.Context`: anulare și termene limită

Pachetul context este standardul de facto pentru propagare anulare, termene limită și valori limitate de-a lungul lanțului de apeluri, pe mai multe gorutine. Toate pachetele standard de „rețea”. (net/http, database/sql, os/exec) acceptă un context.Context ca primul lor parametru.

Interfața

Go
type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key any) any
}
  • Done(): canal care este închis atunci când contextul este anulat.
  • Err(): motivul anulării (context.Canceled sau context.DeadlineExceeded).
  • Deadline(): termen limită opțional.
  • Value(): căutarea valorilor legate de domeniul de aplicare (utilizați cu moderație).

Cele patru funcții de bază

Go
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-bound

Toate formele derivate returnează o funcție cancel: numiți-o întotdeauna (ideal cu defer) pentru a elibera resurse interne, chiar dacă contextul a expirat deja.

Model de timeout

Go
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
}

Dacă queryUser durează mai mult de 2 secunde, ctx.Done() este închis și funcția trebuie să anuleze operația.

Respectarea contextului: selectați pe Done()

Go
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
        }
    }
}

Regula: oriunde funcția ta s-ar putea bloca pentru o lungă perioadă de timp, aceasta trebuie să se ocupe de ctx.Done(). În caz contrar, contextul este „pornit” pentru nimic.

Convenția primului parametru

Go
func Fetch(ctx context.Context, url string) ([]byte, error) { ... }
//        ^^^^^^^^^^^^^^^^^^^
// SEMPRE primo, mai dentro a una struct, mai opzionale
  • ctx ÎNTOTDEAUNA ca prim parametru, numit ctx.
  • Niciodată nu puneți Context ca câmp al unei structuri (excepții foarte rare).
  • Nu trece nil: folosește context.TODO() ca stub.

context.WithValue: cu măsură

Go
type userKey struct{}

ctx := context.WithValue(ctx, userKey{}, currentUser)
// più sotto:
if u, ok := ctx.Value(userKey{}).(*User); ok { ... }

Ghid:

  • NUMAI pentru datele cu sfera de aplicare a cererii (ID-ul cererii, ID-ul urmăririi, identitatea utilizatorului).
  • NICIODATĂ pentru parametrii funcției: treceți-i în mod normal.
  • Chei de tip personalizat neexportat pentru a evita coliziunile.

Propagarea de-a lungul lanțului

Go
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 anulează automat r.Context() atunci când clientul se deconectează sau când manevrătorul revine. Propagând-o tuturor apelurile din aval, întregul arbore al operațiunilor este anulat în cascadă: fără muncă irosită după deconectare.

Încearcă

Exercițiu#go.m7.l5.e1
Încercări: 0Se încarcă…

Creați un context cu un timeout de 1 secundă derivat din context.Background() și nu uitați să apelați cancel cu defer.

Se încarcă editorul...
Afișează indiciu

`context.WithTimeout(parent, d)` returnează `(ctx, cancel)`; sunați întotdeauna anulați.

Soluție disponibilă după 3 încercări

Exercițiu#go.m7.l5.e2
Încercări: 0Se încarcă…

Folosiți <-ctx.Done() într-o selectare pentru a aștepta ca contextul să fie anulat.

Se încarcă editorul...
Afișează indiciu

`ctx.Done()` este un canal care se închide când contextul este anulat.

Soluție disponibilă după 3 încercări

Quiz#go.m7.l5.e3
Gata

Prin convenție, unde merge parametrul ctx într-o semnătură de funcție?

Go
func Fetch(???, url string) ([]byte, error)
Opțiuni de răspuns

Recapitulare

  • context.Context propagă valorile de anulare, termen limită și limite.
  • Background()/TODO() ca rădăcină; WithCancel/WithTimeout/WithDeadline pentru a deriva.
  • Întotdeauna defer cancel() pentru a elibera resurse.
  • Funcțiile „Long” trebuie să select pe ctx.Done() sau să transmită ctx la pachetele standard.
  • Convenție: ctx ca PRIMUL parametru, niciodată în interiorul unei structuri.
  • WithValue numai pentru datele din domeniul de aplicare al cererii (ID de solicitare, ID de urmărire).
  • În net/http, r.Context() este anulat la deconectarea clientului.