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
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.Canceledsaucontext.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ă
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-boundToate 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
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()
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
func Fetch(ctx context.Context, url string) ([]byte, error) { ... }
// ^^^^^^^^^^^^^^^^^^^
// SEMPRE primo, mai dentro a una struct, mai opzionalectxÎNTOTDEAUNA ca prim parametru, numitctx.- Niciodată nu puneți
Contextca câmp al unei structuri (excepții foarte rare). - Nu trece
nil: foloseștecontext.TODO()ca stub.
context.WithValue: cu măsură
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
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ă
Creați un context cu un timeout de 1 secundă derivat din context.Background() și nu uitați să apelați cancel cu defer.
Afișează indiciu
`context.WithTimeout(parent, d)` returnează `(ctx, cancel)`; sunați întotdeauna anulați.
Soluție disponibilă după 3 încercări
Folosiți <-ctx.Done() într-o selectare pentru a aștepta ca contextul să fie anulat.
Afișează indiciu
`ctx.Done()` este un canal care se închide când contextul este anulat.
Soluție disponibilă după 3 încercări
Prin convenție, unde merge parametrul ctx într-o semnătură de funcție?
func Fetch(???, url string) ([]byte, error)Recapitulare
context.Contextpropagă valorile de anulare, termen limită și limite.Background()/TODO()ca rădăcină;WithCancel/WithTimeout/WithDeadlinepentru a deriva.- Întotdeauna
defer cancel()pentru a elibera resurse. - Funcțiile „Long” trebuie să
selectpectx.Done()sau să transmită ctx la pachetele standard. - Convenție:
ctxca PRIMUL parametru, niciodată în interiorul unei structuri. WithValuenumai 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.