Ce face context.WithoutCancel
context.WithoutCancel(ctx) returnează un context care vede toate valorile lui ctx (ID de cerere, utilizator), dar se rupe de anularea lui: când ctx este anulat sau expiră, noul context rămâne activ. Nu are termen limită, Err() este mereu nil, iar Done() returnează nil.
Este util pentru operații care trebuie să se termine chiar dacă cererea originală s-a încheiat: scrierea în jurnalul de audit, trimiterea unui e-mail de confirmare după răspuns, curățenie. Pornești operația cu WithoutCancel(r.Context()) și, de obicei, îi pui propria limită: context.WithTimeout(context.WithoutCancel(ctx), 10*time.Second).
Parametri
| Parametru | Descriere |
|---|---|
parent |
Contextul ale cărui valori se păstrează. |
Ce returnează
Un context nou, fără anulare și fără termen limită.
Exemple
Exemplul 1: Părintele se anulează, copilul nu
package main
import (
"context"
"fmt"
)
type cheie struct{}
func main() {
parinte, cancel := context.WithCancel(context.WithValue(context.Background(), cheie{}, "req-42"))
independent := context.WithoutCancel(parinte)
cancel()
<-parinte.Done()
fmt.Println("Părinte: ", parinte.Err())
fmt.Println("Copil: ", independent.Err(), "| Done=nil:", independent.Done() == nil)
fmt.Println("Valoarea moștenită:", independent.Value(cheie{}))
}
Rezultat
Părinte: context canceled
Copil: <nil> | Done=nil: true
Valoarea moștenită: req-42
Exemplul 2: Jurnal de audit scris după încheierea cererii
Cererea are 50 ms, dar scrierea auditului durează 100 ms. Cu WithoutCancel și o limită proprie de o secundă, auditul se termină.
package main
import (
"context"
"fmt"
"time"
)
func scrieAudit(ctx context.Context, mesaj string) error {
select {
case <-time.After(100 * time.Millisecond):
fmt.Println("Audit salvat:", mesaj)
return nil
case <-ctx.Done():
return ctx.Err()
}
}
func main() {
cerere, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
defer cancel()
fmt.Println("Cu contextul cererii:", scrieAudit(cerere, "Ana a șters produsul 17"))
ctxAudit, cancelAudit := context.WithTimeout(context.WithoutCancel(cerere), time.Second)
defer cancelAudit()
fmt.Println("Cu WithoutCancel: ", scrieAudit(ctxAudit, "Ana a șters produsul 17"))
}
Rezultat
Cu contextul cererii: context deadline exceeded
Audit salvat: Ana a șters produsul 17
Cu WithoutCancel: <nil>
Greșeli frecvente
- Folosești
WithoutCancelfără nicio limită proprie: dacă operația se blochează, nu o mai oprește nimic. AdaugăWithTimeout. - Îl folosești ca să „scapi” de anulare în operații care chiar ar trebui oprite când utilizatorul pleacă (interogări de citire): consumi resurse degeaba.
Comenzi înrudite
context.WithValue: Creează un context copil care poartă o pereche cheie-valoare (ID de cerere, utilizator autentificat), citită cu ctx.Value(cheie).context.WithTimeout: Creează un context care se anulează singur după durata dată; limita de timp standard pentru cereri și interogări.context.AfterFunc: Programează funcția f să ruleze (într-un goroutine nou) când contextul este anulat; stop() renunță la ea.context.Background: Contextul rădăcină, gol: nu se anulează, nu are termen și nici valori; de la el pornesc toate celelalte contexte.