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() // PlaceholderCancellation
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 cancellationTimeout
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 |