Go (Golang) Tutorial 0/45 lessons ~6 min read Lesson 27

    Context Package

    The context package carries deadlines, cancellation signals, and request-scoped values across API boundaries and goroutines.

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    The context package carries deadlines, cancellation signals, and request-scoped values across API boundaries and goroutines. Every HTTP handler receives r.Context(); database and RPC calls should accept ctx context.Context as first parameter.

    context.WithCancel, WithTimeout, and WithDeadline create derived contexts. Never store contexts in structs — pass explicitly. Context values should be request-scoped only (trace IDs), not optional parameters.

    Production outages from ignoring context cancellation are common — this lesson teaches propagation patterns used at Google and every major Go shop.

    The story

    When Kubernetes sends SIGTERM to a pod, your Go HTTP server receives context.Canceled on in-flight requests — ctx.Done() signals goroutines to stop gracefully within the 30-second termination window. Google's gRPC stack threads context.Context through every RPC for deadlines, cancellation, and request-scoped values like trace IDs.

    Pass context.Context as the first parameter to every function that might block — ignoring cancellation leaks goroutines and delays rolling deploys.

    Understanding the topic

    Key concepts

    • context.Background() root; context.TODO() placeholder.
    • WithCancel returns ctx and cancel func — call cancel to propagate.
    • WithTimeout/WithDeadline auto-cancel after duration.
    • ctx.Done() returns channel closed on cancellation.
    • ctx.Err() returns context.Canceled or context.DeadlineExceeded.
    • Value keys should be unexported type to avoid collisions.

    Step-by-step explanation

    1. Derive child context from parent; cancel child affects descendants.
    2. Pass ctx as first param: func Query(ctx context.Context, ...).
    3. Select on ctx.Done() in long loops and blocking ops.
    4. HTTP server cancels ctx when client disconnects.
    5. grpc and database drivers respect ctx cancellation.
    6. cancel() releases resources — defer cancel() after WithCancel.

    Practical code example

    HTTP handler passing context to service with timeout:

    go
    package main
    import (
    "context"
    "fmt"
    "net/http"
    "time"
    )
    type Service struct{}
    func (s *Service) FetchUser(ctx context.Context, id string) (string, error) {
    select {
    case <-time.After(100 * time.Millisecond):
    return fmt.Sprintf("user-%s", id), nil
    case <-ctx.Done():
    return "", ctx.Err()
    }
    }
    func handler(svc *Service) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
    ctx, cancel := context.WithTimeout(r.Context(), 50*time.Millisecond)
    defer cancel()
    user, err := svc.FetchUser(ctx, r.URL.Query().Get("id"))
    if err != nil {
    http.Error(w, err.Error(), http.StatusGatewayTimeout)
    return
    }
    fmt.Fprintln(w, user)
    }
    }
    func main() {
    svc := &Service{}
    http.HandleFunc("/user", handler(svc))
    fmt.Println("listening :8080")
    http.ListenAndServe(":8080", nil)
    }

    Line-by-line code explanation

    • ctx, cancel := context.WithTimeout(parent, 5*time.Second) creates a deadline-bound context.
    • defer cancel() releases timer resources — always call cancel to prevent leaks.
    • ctx.Done() returns a channel closed when the context is canceled or timed out.
    • select { case <-ctx.Done(): return ctx.Err() } exits early on cancellation.
    • context.WithCancel(parent) allows manual cancellation via the returned cancel() function.
    • context.WithValue(ctx, key, val) carries request-scoped metadata — use unexported key types.
    • http.NewRequestWithContext(ctx, ...) propagates cancellation to outbound HTTP calls.
    • never store Context in structs — pass it explicitly through the call chain.

    Key takeaway: Always defer cancel(). Shorter timeout on derived ctx. Propagate r.Context() from HTTP into service layer.

    Real-world use

    Where you'll use this in production

    • Cancelling database queries when HTTP client disconnects.
    • Distributed trace ID propagation via context values.
    • Graceful shutdown cancelling in-flight requests.
    • RPC deadline propagation in microservice chains.

    Best practices

    • Context as first parameter in all I/O functions.
    • defer cancel() immediately after WithCancel/Timeout.
    • Don't use context values for optional func parameters.
    • Honor ctx.Done() in all loops and external calls.
    • Set reasonable timeouts on outbound HTTP and DB calls.
    • Use context.WithoutCancel only when explicitly needed.

    Common mistakes

    • Storing context in struct fields.
    • Ignoring ctx in database/http calls — goroutine leaks.
    • Forgetting defer cancel() — timer leak until parent done.
    • Using string keys for context values — collision risk.
    • Passing nil context — use Background or TODO, never nil.

    Advanced interview questions

    Q1Beginnercontext.Background vs TODO?
    Background for main/tests; TODO when unclear which ctx to use during refactor.
    Q2BeginnerWhen context cancels?
    Manual cancel(), timeout expiry, or parent cancellation.
    Q3IntermediateStore context in struct?
    Anti-pattern — pass explicitly per call for clear lifetime.
    Q4IntermediateHTTP request context cancellation?
    When client disconnects, r.Context() cancelled — stop expensive work.
    Q5AdvancedDesign context propagation across 3 microservices.
    Incoming trace ID in middleware; outgoing grpc/http metadata; timeout budget subtracts elapsed; cancel on first error.

    Summary

    context propagates cancellation, deadlines, and request values. Pass ctx as first parameter; defer cancel() on derived contexts. HTTP handlers must propagate r.Context() to downstream calls. Never store context in structs or use for optional params. Next lesson: file handling with os and io packages.

    Ready to mark this lesson complete?Track your journey across the entire course.