Context and Cancellation

Overview

The context package manages deadlines, cancellation, and request-scoped values across API boundaries.

Creating Contexts

ctx := context.Background()  // Root context
ctx := context.TODO()        // Placeholder

Cancellation

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

go func() {
    select {
    case <-ctx.Done():
        fmt.Println("cancelled:", ctx.Err())
        return
    case <-time.After(time.Hour):
        fmt.Println("completed")
    }
}()

cancel()  // Signal cancellation

Timeout

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

select {
case result := <-doWork(ctx):
    fmt.Println(result)
case <-ctx.Done():
    fmt.Println("timeout:", ctx.Err())
}

Deadline

deadline := time.Now().Add(10 * time.Second)
ctx, cancel := context.WithDeadline(context.Background(), deadline)
defer cancel()

Passing Context

func handleRequest(ctx context.Context) {
    result, err := fetchData(ctx)
    if err != nil {
        return
    }
    processData(ctx, result)
}

func fetchData(ctx context.Context) (Data, error) {
    req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
    return http.DefaultClient.Do(req)
}

Context Values

type key string
const userKey key = "user"

ctx := context.WithValue(ctx, userKey, "alice")

user := ctx.Value(userKey).(string)

Best Practices

  • Pass context as first parameter
  • Never store context in structs
  • Always call cancel() (use defer)
  • Only use context values for request-scoped data

Summary

Function Purpose
WithCancel Manual cancellation
WithTimeout Duration-based timeout
WithDeadline Absolute time limit
WithValue Request-scoped data