The ‘context‘ package in Go is used to carry request-scoped values, cancellation signals, and deadlines across API boundaries and between various processes. It aims to improve code maintainability and reduce the risks associated with misusing timeouts, making it easier to manage the lifecycle of resources.
Let’s explore how to use ‘context‘ package in different situations.
1. Cancellation: You can use a context to cancel a long-running operation or multiple concurrent operations when the user decides to cancel the action.
Here is an example:
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
go func() {
time.Sleep(2 * time.Second)
cancel() // Send the cancel signal after 2 seconds
}()
select {
case <-ctx.Done():
fmt.Println("Canceled:", ctx.Err())
case <-time.After(5 * time.Second):
fmt.Println("Timeout")
}
}
In this example, a background context is created using ‘context.Background()‘, and a ‘cancel‘ function is derived from it using ‘context.WithCancel()‘. The program waits for either the cancel signal or a timeout. The context will be canceled after 2 seconds, printing "Canceled."
2. Timeouts: Using ‘context.WithTimeout()‘, you can set a deadline for an operation to complete, and it’ll automatically be canceled if it takes too long.
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
select {
case <-ctx.Done():
fmt.Println("Operation done:", ctx.Err())
case <-time.After(5 * time.Second):
fmt.Println("Timeout")
}
}
In this example, a context with a 2-second timeout is created, meaning the operation will be canceled after 2 seconds. The result will be "Operation done: context deadline exceeded."
3. Propagate request-scoped values: Passing context values can be helpful for tracing or passing along metadata like request IDs.
package main
import (
"context"
"fmt"
)
type requestKey string
func main() {
ctx := context.WithValue(context.Background(), requestKey("requestID"), "12345")
requestID := ctx.Value(requestKey("requestID"))
if requestID != nil {
fmt.Println("RequestID:", requestID)
} else {
fmt.Println("No RequestID found")
}
}
In this example, we create a new context and store the value ‘"12345"` using the ‘"requestID"` custom key type. Later, we can retrieve the value by using ‘ctx.Value()‘ method.
Remember that when using the ‘context‘ package, always pass context as the first parameter of a function, do not store it in structs, and avoid passing values that are request-shared via context (use proper function parameters for that purpose).