go-context-cancellation

JamesPrial's avatarfrom JamesPrial

Context cancellation patterns for graceful shutdown

⭐2stars🔀0forks📁View on GitHub🕐Updated Dec 28, 2025⬇️1downloads

When & Why to Use This Skill

This Claude skill provides essential design patterns and best practices for Go (Golang) context cancellation. It focuses on implementing graceful shutdowns, managing goroutine lifecycles, and preventing resource leaks by correctly propagating context and handling timeout signals in high-performance concurrent applications.

Use Cases

  • Graceful Shutdown: Implementing clean termination logic in microservices to ensure in-flight requests are processed before the service stops.
  • Timeout Management: Setting execution limits on database queries and API calls using context.WithTimeout to prevent system-wide hanging and cascading failures.
  • Resource Leak Prevention: Ensuring goroutines and system resources are properly released by following the 'defer cancel()' pattern and monitoring the Done channel.
  • Concurrent Workflow Control: Coordinating multiple background workers by broadcasting cancellation signals across complex task trees to maintain system responsiveness.
namego-context-cancellation
descriptionContext cancellation patterns for graceful shutdown

Context Cancellation

Pattern

Pass context.Context as first parameter. Check ctx.Done() in goroutines and long operations.

CORRECT

func ProcessItems(ctx context.Context, items []string) error {
    for _, item := range items {
        select {
        case <-ctx.Done():
            return ctx.Err()
        default:
            if err := processItem(item); err != nil {
                return err
            }
        }
    }
    return nil
}

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

    if err := ProcessItems(ctx, items); err != nil {
        log.Printf("processing failed: %v", err)
    }
}

WRONG - No context checking

func ProcessItems(items []string) error {
    for _, item := range items {
        // No way to cancel - runs forever if stuck
        if err := processItem(item); err != nil {
            return err
        }
    }
    return nil
}

Rules

  1. Context is first parameter: func Do(ctx context.Context, ...)
  2. Always call cancel() via defer to prevent leaks
  3. Check ctx.Done() in loops and before expensive operations
  4. Propagate context to downstream calls
  5. Use context.WithTimeout or WithDeadline for time limits

Common Patterns

// HTTP server with context
func handler(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context() // Request context
    result, err := fetchData(ctx)
    // ...
}

// Worker with cancellation
func worker(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            return
        case work := <-workCh:
            process(work)
        }
    }
}