Il Filo D'Oro: Gestire i cicli di vita distribuiti in Go

In un mondo monolitico, una stack trace era solitamente sufficiente per diagnosticare un fallimento. In un ambiente Go cloud-native, dove una singola richiesta potrebbe innescare tre microservizi e un’attività in background asincrona, la stack trace è morta.

Il nuovo “Filo D’Oro” è context.Context.

Se non stai gestendo correttamente il tuo context, non stai solo perdendo visibilità; stai perdendo il controllo sul ciclo di vita del tuo sistema.

1. La Propagazione dell’Intento

La funzione più basilare del context è l’annullamento (cancellation). Nei sistemi ad alto volume, il lavoro “orfano” è un killer silenzioso delle prestazioni.

Immagina che un utente avvii la generazione di un report pesante attraverso il tuo Gateway. A metà strada, aggiorna il browser o perde la connessione. Se il tuo Gateway va in timeout ma non propaga quel segnale di annullamento a valle, i tuoi servizi Go continueranno a macinare, sprecando CPU e connessioni al DB per un risultato che non verrà mai consegnato.

Rispetta sempre ctx.Done().

1
2
3
4
5
func HeavyDatabaseTask(ctx context.Context, db *sql.DB) error {
    // Passa ctx direttamente al driver
    // Il driver interromperà la query se il context viene annullato
    return db.QueryRowContext(ctx, "SELECT ...").Scan(&result)
}

2. Dai “Log Solitari” al Tracciamento Strutturato

Un log è solo una stringa senza una casa. Per rendere i log utili in un sistema distribuito, devono essere correlati. Utilizzando il context per trasportare le informazioni degli span di OpenTelemetry, ogni riga di log prodotta durante una richiesta diventa parte di una storia più grande.

L’utilizzo di slog (Structured Logging) nativo di Go con il context assicura che i tuoi log e le tue tracce nascano insieme:

1
2
3
4
5
6
7
8
9
// Standard 2026: Logging strutturato context-aware
func ProcessOrder(ctx context.Context, orderID string) {
    ctx, span := otel.Tracer("order-service").Start(ctx, "ProcessOrder")
    defer span.End()

    // slog.InfoContext estrae automaticamente il TraceID da ctx 
    // se l'handler è configurato per OpenTelemetry.
    slog.InfoContext(ctx, "elaborazione ordine in corso", "order_id", orderID)
}

Questo permette a Google Cloud Trace di mostrarti esattamente dov’è il collo di bottiglia: non solo che “qualcosa è lento”, ma che “la query al database del Servizio B ha richiesto 800ms”.

3. Context Attraverso i Confini (Pub/Sub e Oltre)

Il filo non dovrebbe spezzarsi quando incontri una coda di messaggi. Quando pubblichi un messaggio su GCP Pub/Sub, dovresti iniettare il Trace ID negli attributi del messaggio. Sul lato del ricevente, il worker dovrebbe estrarre quell’ID e avviare un nuovo context con lo stesso Trace ID.

Questo “Collegamento” garantisce che i tuoi worker in background non siano invisibili. Puoi tracciare una richiesta dal POST HTTP iniziale fino all’email finale in background inviata cinque minuti dopo.

Sintesi: Il Context Non È Opzionale

Nel 2026, context.Context è il parametro più importante nelle tue funzioni Go. È il ponte tra il tuo codice e l’infrastruttura sottostante. Padroneggiando la propagazione del context, passi dalla costruzione di “scatole nere” alla costruzione di sistemi trasparenti e resilienti che sono un piacere da debuggare.

Smetti di passare context di background. Inizia a passare intenti.