go-context-cancellation
Context cancellation patterns for graceful shutdown
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.
| name | go-context-cancellation |
|---|---|
| description | Context 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
- Context is first parameter:
func Do(ctx context.Context, ...) - Always call
cancel()viadeferto prevent leaks - Check
ctx.Done()in loops and before expensive operations - Propagate context to downstream calls
- Use
context.WithTimeoutorWithDeadlinefor 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)
}
}
}