context.Background în Go

Contextul rădăcină, gol: nu se anulează, nu are termen și nici valori; de la el pornesc toate celelalte contexte.

Sintaxă
func Background() Context
func TODO() Context

Ce face context.Background

context.Background() returnează un context gol: nu este anulat niciodată (Done() returnează nil), nu are termen limită și nu conține valori. Este rădăcina arborelui de contexte: îl folosești în main, la pornirea programului, în teste și în sarcinile de fundal, apoi creezi din el contexte cu limită de timp sau anulare (WithTimeout, WithCancel, WithValue).

context.TODO() este identic ca funcționare, dar transmite un mesaj cititorului: „aici ar trebui să vină un context real, dar încă nu am unul”. Se folosește temporar, când adaugi suport pentru context unei funcții ai cărei apelanți nu dau încă un context. Uneltele de analiză pot căuta apelurile TODO rămase.

Într-un handler HTTP nu pornești de la Background: folosești r.Context(), care se anulează când clientul pleacă.

Ce returnează

Un context.Context gol. Ambele funcții returnează mereu aceeași valoare.

Exemple

Exemplul 1: Proprietățile contextului rădăcină

package main

import (
	"context"
	"fmt"
)

func main() {
	contexte := []struct {
		nume string
		ctx  context.Context
	}{{"Background", context.Background()}, {"TODO", context.TODO()}}
	for _, c := range contexte {
		nume, ctx := c.nume, c.ctx
		_, areTermen := ctx.Deadline()
		fmt.Printf("%-10s Done=nil:%v Err=%v termen:%v valoare:%v text:%s\n",
			nume, ctx.Done() == nil, ctx.Err(), areTermen, ctx.Value("x"), ctx)
	}
}

Rezultat

Background Done=nil:true Err=<nil> termen:false valoare:<nil> text:context.Background
TODO       Done=nil:true Err=<nil> termen:false valoare:<nil> text:context.TODO

Exemplul 2: Punctul de pornire în main

Din Background se creează un context cu limită de timp, transmis apoi funcțiilor.

package main

import (
	"context"
	"fmt"
	"time"
)

func sincronizeazaStoc(ctx context.Context) error {
	select {
	case <-time.After(20 * time.Millisecond):
		fmt.Println("Stoc sincronizat")
		return nil
	case <-ctx.Done():
		return ctx.Err()
	}
}

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	if err := sincronizeazaStoc(ctx); err != nil {
		fmt.Println("eroare:", err)
	}
}

Rezultat

Stoc sincronizat

Exemplul 3: TODO pentru cod în curs de schimbare

package main

import (
	"context"
	"fmt"
)

// TrimiteEmail primește acum un context, dar apelantul vechi nu are încă unul.
func TrimiteEmail(ctx context.Context, catre string) error {
	if err := ctx.Err(); err != nil {
		return err
	}
	fmt.Println("E-mail trimis către", catre)
	return nil
}

func notificareVeche(catre string) {
	TrimiteEmail(context.TODO(), catre) // de înlocuit cu contextul cererii
}

func main() {
	notificareVeche("ana@example.ro")
}

Rezultat

E-mail trimis către ana@example.ro

Greșeli frecvente

  • Folosești context.Background() în adâncul codului (în handler-e, în funcții de bibliotecă) în loc să primești contextul ca parametru: anularea de sus nu mai ajunge la operații.
  • Transmiți nil când nu ai un context: funcțiile se pot opri cu panică. Dă context.TODO().

Comenzi înrudite

  • context.Context: Interfața care duce prin program semnalul de anulare, termenul limită și valori legate de o cerere (ctx).
  • context.WithTimeout: Creează un context care se anulează singur după durata dată; limita de timp standard pentru cereri și interogări.
  • context.WithCancel: Creează un context copil și o funcție cancel; apelul cancel() anunță toate goroutine-urile care îl folosesc să se oprească.
  • context.WithValue: Creează un context copil care poartă o pereche cheie-valoare (ID de cerere, utilizator autentificat), citită cu ctx.Value(cheie).