Context-Based Termination
Understanding Context in Go
Context is a powerful mechanism in Go for carrying deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
Context Types
Context Type |
Description |
Use Case |
context.Background() |
Empty root context |
Initial context creation |
context.TODO() |
Placeholder context |
Unclear cancellation requirements |
context.WithCancel() |
Manually cancellable context |
Controlled goroutine termination |
context.WithDeadline() |
Time-based cancellation |
Request timeouts |
context.WithTimeout() |
Duration-based cancellation |
Limiting operation time |
context.WithValue() |
Carrying request-scoped values |
Passing metadata |
Context Propagation Workflow
flowchart TD
A[Parent Context] --> B[Child Context 1]
A --> C[Child Context 2]
B --> D[Grandchild Context]
C --> E[Grandchild Context]
Comprehensive Context Example
package main
import (
"context"
"fmt"
"time"
)
func performTask(ctx context.Context, taskID int) {
select {
case <-time.After(2 * time.Second):
fmt.Printf("Task %d completed successfully\n", taskID)
case <-ctx.Done():
fmt.Printf("Task %d cancelled: %v\n", taskID, ctx.Err())
}
}
func main() {
// Create a context with 1-second timeout
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
// Start multiple tasks
for i := 1; i <= 3; i++ {
go performTask(ctx, i)
}
// Wait for context to complete
<-ctx.Done()
time.Sleep(2 * time.Second)
}
Advanced Context Techniques
Combining Cancellation and Values
package main
import (
"context"
"fmt"
)
type userKey string
func processRequest(ctx context.Context) {
// Extract user from context
user, ok := ctx.Value(userKey("user")).(string)
if !ok {
fmt.Println("No user in context")
return
}
select {
case <-ctx.Done():
fmt.Println("Request cancelled")
default:
fmt.Printf("Processing request for user: %s\n", user)
}
}
func main() {
ctx := context.WithValue(
context.Background(),
userKey("user"),
"labex_developer"
)
ctx, cancel := context.WithCancel(ctx)
defer cancel()
processRequest(ctx)
}
Context Best Practices
- Always pass context as the first parameter
- Do not store contexts in structs
- Use
context.Background()
only in main or top-level functions
- Cancel contexts as soon as their purpose is complete
- Context has minimal overhead
- Prefer passing context explicitly
- Use context for coordinating cancellation and timeouts
At LabEx, we recommend using context as a standard pattern for managing concurrent operations and request lifecycles.
When to Use Context
- API request handling
- Database query management
- Microservice communication
- Long-running background tasks
- Graceful server shutdown
Mastering context-based termination enables developers to write more robust and responsive Go applications.