Go Concurrency Patterns: Context - The Go Blog[web search]
- Install Go
- A Tour of Go
- Go Documentation
- Go Mailing List
- Go on Google+
- Go+ Community
- Go on Twitter
29 July 2014
In Go servers, each incoming request is handled in its own goroutine. Request handlers often start additional goroutines to access backends such as databases and RPC services. The set of goroutines working on a request typically needs access to request-specific values such as the identity of the end user, authorization tokens, and the request's deadline. When a request is canceled or times out, all the goroutines working on that request should exit quickly so the system can reclaim any resources they are using.
At Google, we developed a
context package that makes it easy to pass
request-scoped values, cancelation signals, and deadlines across API boundaries
to all the goroutines involved in handling a request.
The package is publicly available as
This article describes how to use the package and provides a complete working
The core of the
context package is the
(This description is condensed; the godoc is authoritative.)
Done method returns a channel that acts as a cancelation signal to
functions running on behalf of the
Context: when the channel is closed, the
functions should abandon their work and return.
Err method returns an error indicating why the
Context was canceled.
The Pipelines and Cancelation article discusses the
channel idiom in more detail.
Context does not have a
Cancel method for the same reason the
channel is receive-only: the function receiving a cancelation signal is usually
not the one that sends the signal.
In particular, when a parent operation starts goroutines for sub-operations,
those sub-operations should not be able to cancel the parent.
WithCancel function (described below) provides a way to cancel a
Context is safe for simultaneous use by multiple goroutines.
Code can pass a single
Context to any number of goroutines and cancel that
Context to signal all of them.
Deadline method allows functions to determine whether they should start
work at all; if too little time is left, it may not be worthwhile.
Code may also use a deadline to set timeouts for I/O operations.
Value allows a
Context to carry request-scoped data.
That data must be safe for simultaneous use by multiple goroutines.
context package provides functions to derive new
Context values from
These values form a tree: when a
Context is canceled, all
from it are also canceled.
Background is the root of any
Context tree; it is never canceled:
WithTimeout return derived
Context values that can be
canceled sooner than the parent
Context associated with an incoming request is typically canceled when the
request handler returns.
WithCancel is also useful for canceling redundant requests when using multiple
WithTimeout is useful for setting a deadline on requests to backend servers:
WithValue provides a way to associate request-scoped values with a
The best way to see how to use the
context package is through a worked
Example: Google Web Search
Our example is an HTTP server that handles URLs like
/search?q=golang&timeout=1s by forwarding the query "golang" to the
Google Web Search API and
rendering the results.
timeout parameter tells the server to cancel the request after that
The code is split across three packages:
- server provides the
mainfunction and the handler for
- userip provides functions for extracting a user IP address from a request and associating it with a
- google provides the
Searchfunction for sending a query to Google.
The server program
The server program handles requests like
/search?q=golang by serving the first few Google search results for
handleSearch to handle the
The handler creates an initial
ctx and arranges for it to be
canceled when the handler returns.
If the request includes the
timeout URL parameter, the
Context is canceled
automatically when the timeout elapses:
The handler extracts the query from the request and extracts the client's IP
address by calling on the
The client's IP address is needed for backend requests, so
attaches it to
The handler calls
ctx and the
If the search succeeds, the handler renders the results:
The userip package provides functions for
extracting a user IP address from a request and associating it with a
Context provides a key-value mapping, where the keys and values are both of
Key types must support equality, and values must be safe for simultaneous use by
userip hide the details of this mapping and provide
strongly-typed access to a specific
To avoid key collisions,
userip defines an unexported type
key and uses
a value of this type as the context key:
FromRequest extracts a
userIP value from an
NewContext returns a new
Context that carries a provided
FromContext extracts a
userIP from a
The google.Search function makes an HTTP request
to the Google Web Search API
and parses the JSON-encoded result.
It accepts a
ctx and returns immediately if
closed while the request is in flight.
The Google Web Search API request includes the search query and the user IP as query parameters:
Search uses a helper function,
httpDo, to issue the HTTP request and cancel
ctx.Done is closed while the request or response is being processed.
Search passes a closure to
httpDo handle the HTTP response:
httpDo function runs the HTTP request and processes its response in a new
It cancels the request if
ctx.Done is closed before the goroutine exits:
Adapting code for Contexts
Many server frameworks provide packages and types for carrying request-scoped
We can define new implementations of the
Context interface to bridge between
code using existing frameworks and code that expects a
For example, Gorilla's
package allows handlers to associate data with incoming requests by providing a
mapping from HTTP requests to key-value pairs.
In gorilla.go, we provide a
Value method returns the values associated with a
specific HTTP request in the Gorilla package.
Other packages have provided cancelation support similar to
For example, Tomb provides a
method that signals cancelation by closing a
Tomb also provides methods to wait for those goroutines to exit, similar to
In tomb.go, we provide a
Context implementation that
is canceled when either its parent
Context is canceled or a provided
At Google, we require that Go programmers pass a
Context parameter as the
first argument to every function on the call path between incoming and outgoing
This allows Go code developed by many different teams to interoperate well.
It provides simple control over timeouts and cancelation and ensures that
critical values like security credentials transit Go programs properly.
Server frameworks that want to build on
Context should provide implementations
Context to bridge between their packages and those that expect a
Their client libraries would then accept a
Context from the calling code.
By establishing a common interface for request-scoped data and cancelation,
Context makes it easier for package developers to share code for creating
By Sameer Ajmani