Context
suggest changePackage context
in standard library provides type Context
which is hard to explain because it has multiple uses.
Here are the most common uses of context.Context
:
- context with timeout (deadline) is a generic way to implement timeouts for functions that can possibly take a long time where we want an option to abort them if they exceed the timeout
- context with cancellation is a generic way to cancel a goroutine
- context with value is a way to associate arbitrary value with a context
Creating a context
In most cases you’ll be calling existing API that requires context.Context
.
If you don’t have one, use context.TODO()
or context.Background()
functions to create it. Read about the difference.
context.Context
is an immutable (read-only) value so you can’t modify it.
To create e.g. a context with value, you call context.WithValue()
which returns a new context that wraps existing context and adds additional information.
context.Context
is an interface so you could pass nil
but it’s not recommended.
Many APIs expect non-nil value and will crash if passed nil
so it’s best to always pass one created with context.Background()
or context.TODO()
.
There is no performance issue because those functions return shared, global variables (yay immutability!).
Using context with timeout to set timeout for HTTP requests
Repeating an example from HTTP client article here’s a way to create a context with timeout to ensure HTTP GET request doesn’t hang forever:
// httpbin.org is a service for testing HTTP client
// this URL waits 3 seconds before returning a response
uri := "https://httpbin.org/delay/3"
req, err := http.NewRequest("GET", uri, nil)
if err != nil {
log.Fatalf("http.NewRequest() failed with '%s'\n", err)
}
// create a context indicating 100 ms timeout
ctx, _ := context.WithTimeout(context.Background(), time.Millisecond*100)
// get a new request based on original request but with the context
req = req.WithContext(ctx)
resp, err := http.DefaultClient.Do(req)
if err != nil {
// the request should timeout because we want to wait max 100 ms
// but the server doesn't return response for 3 seconds
log.Fatalf("http.DefaultClient.Do() failed with:\n'%s'\n", err)
}
defer resp.Body.Close()
HTTP client knows how to interpret context with a timeout. You just need to create and provide it.