A
Context
carries deadlines, cancellation signals, and other request-scoped values across API boundaries and goroutines.Why
- Timeout
- Deadline
- Channel
- Share data
Scenarios
- Web request
- HTTP request
- gRPC
How to use
Create a context
ctx, cancel := context.Background()
ctx, cancel := context.TODO() // less common
Use withValue to share data
Imagine a
map
inside context.package main
import (
"context"
"fmt"
)
func main() {
ctx := context.Background()
ctx = addValue(ctx)
readValue(ctx)
}
func addValue(ctx context.Context) context.Context {
return context.WithValue(ctx, "key", "test-value")
}
func readValue(ctx context.Context) {
val := ctx.Value("key")
fmt.Println(val) // test-value
}
Use cancellation to terminate all process in the same pipeline
Ex: A client close their browser, then we should stop querying data from the database.
If cancellation is triggered, we receive messages from
ctx.Done()
. operation1 failed after 100 ms, and then operation2 is halted.func operation1(ctx context.Context) error {
// Let's assume that this operation failed for some reason
// We use time.Sleep to simulate a resource intensive operation
time.Sleep(100 * time.Millisecond)
return errors.New("failed")
}
func operation2(ctx context.Context) {
// We use a similar pattern to the HTTP server
// that we saw in the earlier example
select {
case <-time.After(500 * time.Millisecond):
fmt.Println("done")
case <-ctx.Done():
fmt.Println("halted operation2")
}
}
func main() {
// Create a new context
ctx := context.Background()
// Create a new context, with its cancellation function
// from the original context
ctx, cancel := context.WithCancel(ctx)
// Run two operations: one in a different go routine
go func() {
err := operation1(ctx)
// If this operation returns an error
// cancel all operations using this context
if err != nil {
cancel()
}
}()
// Run operation2 with the same context we use for operation1
operation2(ctx)
}
Use timeout and deadline so that app does not wait forever
// The context will be cancelled after 3 seconds
// If it needs to be cancelled earlier, the `cancel` function can
// be used, like before
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
// Setting a context deadline is similar to setting a timeout, except
// you specify a time when you want the context to cancel, rather than a duration.
// Here, the context will be cancelled on 2009-11-10 23:00:00
ctx, cancel := context.WithDeadline(ctx, time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC))