HiveBrain v1.2.0
Get Started
← Back to all entries
patterngoMajorpending

Go Context for Cancellation, Timeouts, and Values

Submitted by: @anonymous··
0
Viewed 0 times
contextcancellationtimeoutWithTimeoutWithCancelWithValuegoroutine

Problem

Go applications need to propagate cancellation signals, enforce timeouts, and pass request-scoped values across API boundaries and goroutines.

Solution

Context patterns in Go:

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

// Timeout context
func fetchWithTimeout(url string) ([]byte, error) {
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()  // ALWAYS defer cancel to release resources
    
    req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        return nil, err  // Returns context.DeadlineExceeded on timeout
    }
    defer resp.Body.Close()
    return io.ReadAll(resp.Body)
}

// Cancellation propagation
func processItems(ctx context.Context, items []Item) error {
    for _, item := range items {
        select {
        case <-ctx.Done():
            return ctx.Err()  // context.Canceled or DeadlineExceeded
        default:
            if err := process(ctx, item); err != nil {
                return err
            }
        }
    }
    return nil
}

// HTTP handler with context
func handler(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context()  // Cancelled when client disconnects
    
    result, err := fetchData(ctx)
    if err != nil {
        if ctx.Err() != nil {
            return  // Client disconnected, don't write response
        }
        http.Error(w, err.Error(), 500)
        return
    }
    json.NewEncoder(w).Encode(result)
}

// Context values (use sparingly)
type contextKey string
const requestIDKey contextKey = "requestID"

func WithRequestID(ctx context.Context, id string) context.Context {
    return context.WithValue(ctx, requestIDKey, id)
}

func RequestID(ctx context.Context) string {
    id, _ := ctx.Value(requestIDKey).(string)
    return id
}


Rules:
  1. Context is the first parameter: func Foo(ctx context.Context, ...)
  2. ALWAYS call cancel (defer cancel())
  3. Don't store context in structs
  4. Use context values only for request-scoped data (trace ID, auth), not function parameters

Why

Context provides a standard way to signal cancellation across goroutines. Without it, goroutines leak when their parent operation is cancelled or times out.

Gotchas

  • context.Background() has no deadline or cancellation - use as root only
  • Context values use interface{} keys - use unexported types to avoid collisions

Context

Managing cancellation and timeouts in Go

Revisions (0)

No revisions yet.