Ce face context.WithCancelCause
Cu WithCancel, după anulare ctx.Err() spune doar context canceled, fără motiv. WithCancelCause returnează o funcție cancel(err) care primește o eroare: motivul. ctx.Err() rămâne context.Canceled (pentru compatibilitate), dar context.Cause(ctx) returnează eroarea dată de tine.
context.Cause funcționează pe orice context: pentru un context activ returnează nil, pentru unul anulat fără motiv returnează același lucru ca Err(), iar pentru copiii unui context anulat cu motiv returnează motivul părintelui. cancel(nil) pune motivul context.Canceled.
Parametri
| Parametru | Descriere |
|---|---|
parent |
Contextul părinte. |
Ce returnează
Contextul și funcția cancel(cause error). Cause returnează motivul (error) sau nil.
Exemple
Exemplul 1: Motivul anulării
package main
import (
"context"
"errors"
"fmt"
)
var ErrStocEpuizat = errors.New("stoc epuizat")
func main() {
ctx, cancel := context.WithCancelCause(context.Background())
fmt.Println("Activ: Err =", ctx.Err(), "Cause =", context.Cause(ctx))
cancel(ErrStocEpuizat)
fmt.Println("Err: ", ctx.Err())
fmt.Println("Cause:", context.Cause(ctx))
fmt.Println("Este stoc epuizat:", errors.Is(context.Cause(ctx), ErrStocEpuizat))
copil, cancelCopil := context.WithCancel(ctx)
defer cancelCopil()
fmt.Println("Cause la copil:", context.Cause(copil))
}
Rezultat
Activ: Err = <nil> Cause = <nil>
Err: context canceled
Cause: stoc epuizat
Este stoc epuizat: true
Cause la copil: stoc epuizat
Exemplul 2: Primul lucrător care eșuează oprește grupul
Lucrătorul care găsește o eroare anulează contextul cu ea; ceilalți se opresc, iar main află motivul real.
package main
import (
"context"
"fmt"
"sync"
"time"
)
func valideaza(ctx context.Context, cancel context.CancelCauseFunc, fisier string) {
if fisier == "date.csv" {
cancel(fmt.Errorf("%s: linia 7 are un CNP invalid", fisier))
return
}
select {
case <-time.After(time.Second):
case <-ctx.Done():
}
}
func main() {
ctx, cancel := context.WithCancelCause(context.Background())
defer cancel(nil)
var wg sync.WaitGroup
for _, f := range []string{"clienti.csv", "date.csv", "produse.csv"} {
wg.Go(func() { valideaza(ctx, cancel, f) })
}
wg.Wait()
fmt.Println("Err: ", ctx.Err())
fmt.Println("Motiv:", context.Cause(ctx))
}
Rezultat
Err: context canceled
Motiv: date.csv: linia 7 are un CNP invalid
Greșeli frecvente
- Te uiți doar la
ctx.Err()și te miri că motivul lipsește.Err()rămânecontext.Canceled; motivul se citește cucontext.Cause(ctx).
Comenzi înrudite
context.WithCancel: Creează un context copil și o funcție cancel; apelul cancel() anunță toate goroutine-urile care îl folosesc să se oprească.context.WithTimeoutCause: Ca WithTimeout și WithDeadline, dar la expirare context.Cause(ctx) returnează eroarea ta, nu doar DeadlineExceeded.errors.Is: Verifică dacă eroarea err este target sau o conține, căutând prin toate erorile împachetate cu %w sau Join.