Direct naar de hoofdinhoud
Module 7 · Les 5 van 535/50 in de cursus~14 min
Modulelessen (5/5)

`context.Context`: annulering en deadlines

Het pakket context is de de facto standaard voor propagatie annuleringen, deadlines en bereikgebonden waarden in de belketen, over meerdere goroutines. Alle standaard "netwerk" pakketten (net/http, database/sql, os/exec) accepteer een context.Context als hun eerste parameter.

De interface

Go
type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key any) any
}
  • Done(): kanaal dat wordt gesloten wanneer de context wordt geannuleerd.
  • Err(): reden voor annulering (context.Canceled of context.DeadlineExceeded).
  • Deadline(): optionele deadline.
  • Value(): opzoeken van bereikgebonden waarden (spaarzaam gebruiken).

De vier basisfuncties

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

Alle afgeleide vormen retourneren een cancel functie: roep deze altijd aan (idealiter met defer) om interne bronnen vrij te geven, zelfs als de context is al verlopen.

Time-out patroon

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
}

Als queryUser langer dan 2 seconden duurt, wordt ctx.Done() gesloten en de functie moet de bewerking afbreken.

De context respecteren: selecteer op 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
        }
    }
}

De regel: overal waar uw functie voor langere tijd blokkeert, wordt het moet ctx.Done() verwerken. Anders wordt de context "aangezet". niets.

Conventie van eerste parameters

Go
func Fetch(ctx context.Context, url string) ([]byte, error) { ... }
//        ^^^^^^^^^^^^^^^^^^^
// SEMPRE primo, mai dentro a una struct, mai opzionale
  • ctx ALTIJD als de eerste parameter, genaamd ctx.
  • Nooit plaats Context als een veld van een structuur (zeer zeldzame uitzonderingen).
  • Nooit passeer nil: gebruik context.TODO() als stub.

context.WithValue: spaarzaam

Go
type userKey struct{}

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

Richtlijnen:

  • ALLEEN voor verzoekgerichte gegevens (verzoek-ID, trace-ID, gebruikersidentiteit).
  • NOOIT voor functieparameters: geef ze normaal door.
  • Sleutels van een aangepast, niet-geëxporteerd type om botsingen te voorkomen.

Voortplanting langs de keten

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 annuleert automatisch r.Context() wanneer de client de verbinding verbreekt of wanneer de handler terugkeert. Door het aan iedereen te verspreiden downstream-oproepen wordt de hele boom van bewerkingen geannuleerd cascade: geen verspild werk na ontkoppeling.

Probeer het

Oefening#go.m7.l5.e1
Pogingen: 0Laden…

Creëer een context met een time-out van 1 seconde afgeleid van context.Background() en vergeet niet om cancel met uitstel aan te roepen.

Editor laden…
Toon hint

`context.WithTimeout(parent, d)` retourneert `(ctx, annuleren)`; altijd bellen annuleren.

Oplossing beschikbaar na 3 pogingen

Oefening#go.m7.l5.e2
Pogingen: 0Laden…

Gebruik <-ctx.Done() in een selectie om te wachten tot de context wordt geannuleerd.

Editor laden…
Toon hint

`ctx.Done()` is een kanaal dat sluit wanneer de context wordt geannuleerd.

Oplossing beschikbaar na 3 pogingen

Quiz#go.m7.l5.e3
Klaar

Waar gaat de ctx-parameter volgens afspraak naartoe in een functiehandtekening?

Go
func Fetch(???, url string) ([]byte, error)
Antwoordmogelijkheden

Samenvatten

  • context.Context propageert annulerings-, deadline- en bereikgebonden waarden.
  • Background()/TODO() als root; WithCancel/WithTimeout/WithDeadline om af te leiden.
  • Altijd defer cancel() om bronnen vrij te geven.
  • "Lange" functies moeten select op ctx.Done() of ctx doorgeven aan standaardpakketten.
  • Conventie: ctx als de FIRST parameter, nooit binnen een struct.
  • WithValue alleen voor gegevens op aanvraaggebied (aanvraag-ID, trace-ID).
  • In net/http wordt r.Context() geannuleerd wanneer de clientverbinding wordt verbroken.