github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/blog/content/context.article (about) 1 Go Concurrency Patterns: Context 2 29 Jul 2014 3 Tags: concurrency, cancelation, cancellation, context 4 5 Sameer Ajmani 6 7 * Introduction 8 9 In Go servers, each incoming request is handled in its own goroutine. 10 Request handlers often start additional goroutines to access backends such as 11 databases and RPC services. 12 The set of goroutines working on a request typically needs access to 13 request-specific values such as the identity of the end user, authorization 14 tokens, and the request's deadline. 15 When a request is canceled or times out, all the goroutines working on that 16 request should exit quickly so the system can reclaim any resources they are 17 using. 18 19 At Google, we developed a `context` package that makes it easy to pass 20 request-scoped values, cancelation signals, and deadlines across API boundaries 21 to all the goroutines involved in handling a request. 22 The package is publicly available as 23 [[http://godoc.org/golang.org/x/net/context][golang.org/x/net/context]]. 24 This article describes how to use the package and provides a complete working 25 example. 26 27 * Context 28 29 The core of the `context` package is the `Context` type: 30 31 .code context/interface.go /A Context/,/^}/ 32 33 (This description is condensed; the 34 [[http://godoc.org/golang.org/x/net/context][godoc]] is authoritative.) 35 36 The `Done` method returns a channel that acts as a cancelation signal to 37 functions running on behalf of the `Context`: when the channel is closed, the 38 functions should abandon their work and return. 39 The `Err` method returns an error indicating why the `Context` was canceled. 40 The [[/pipelines][Pipelines and Cancelation]] article discusses the `Done` 41 channel idiom in more detail. 42 43 A `Context` does _not_ have a `Cancel` method for the same reason the `Done` 44 channel is receive-only: the function receiving a cancelation signal is usually 45 not the one that sends the signal. 46 In particular, when a parent operation starts goroutines for sub-operations, 47 those sub-operations should not be able to cancel the parent. 48 Instead, the `WithCancel` function (described below) provides a way to cancel a 49 new `Context` value. 50 51 A `Context` is safe for simultaneous use by multiple goroutines. 52 Code can pass a single `Context` to any number of goroutines and cancel that 53 `Context` to signal all of them. 54 55 The `Deadline` method allows functions to determine whether they should start 56 work at all; if too little time is left, it may not be worthwhile. 57 Code may also use a deadline to set timeouts for I/O operations. 58 59 `Value` allows a `Context` to carry request-scoped data. 60 That data must be safe for simultaneous use by multiple goroutines. 61 62 ** Derived contexts 63 64 The `context` package provides functions to _derive_ new `Context` values from 65 existing ones. 66 These values form a tree: when a `Context` is canceled, all `Contexts` derived 67 from it are also canceled. 68 69 `Background` is the root of any `Context` tree; it is never canceled: 70 71 .code context/interface.go /Background returns/,/func Background/ 72 73 `WithCancel` and `WithTimeout` return derived `Context` values that can be 74 canceled sooner than the parent `Context`. 75 The `Context` associated with an incoming request is typically canceled when the 76 request handler returns. 77 `WithCancel` is also useful for canceling redundant requests when using multiple 78 replicas. 79 `WithTimeout` is useful for setting a deadline on requests to backend servers: 80 81 .code context/interface.go /WithCancel/,/func WithTimeout/ 82 83 `WithValue` provides a way to associate request-scoped values with a `Context`: 84 85 .code context/interface.go /WithValue/,/func WithValue/ 86 87 The best way to see how to use the `context` package is through a worked 88 example. 89 90 * Example: Google Web Search 91 92 Our example is an HTTP server that handles URLs like 93 `/search?q=golang&timeout=1s` by forwarding the query "golang" to the 94 [[https://developers.google.com/web-search/docs/][Google Web Search API]] and 95 rendering the results. 96 The `timeout` parameter tells the server to cancel the request after that 97 duration elapses. 98 99 The code is split across three packages: 100 101 - [[context/server/server.go][server]] provides the `main` function and the handler for `/search`. 102 - [[context/userip/userip.go][userip]] provides functions for extracting a user IP address from a request and associating it with a `Context`. 103 - [[context/google/google.go][google]] provides the `Search` function for sending a query to Google. 104 105 ** The server program 106 107 The [[context/server/server.go][server]] program handles requests like 108 `/search?q=golang` by serving the first few Google search results for `golang`. 109 It registers `handleSearch` to handle the `/search` endpoint. 110 The handler creates an initial `Context` called `ctx` and arranges for it to be 111 canceled when the handler returns. 112 If the request includes the `timeout` URL parameter, the `Context` is canceled 113 automatically when the timeout elapses: 114 115 .code context/server/server.go /func handleSearch/,/defer cancel/ 116 117 The handler extracts the query from the request and extracts the client's IP 118 address by calling on the `userip` package. 119 The client's IP address is needed for backend requests, so `handleSearch` 120 attaches it to `ctx`: 121 122 .code context/server/server.go /Check the search query/,/userip.NewContext/ 123 124 The handler calls `google.Search` with `ctx` and the `query`: 125 126 .code context/server/server.go /Run the Google search/,/elapsed/ 127 128 If the search succeeds, the handler renders the results: 129 130 .code context/server/server.go /resultsTemplate/,/}$/ 131 132 ** Package userip 133 134 The [[context/userip/userip.go][userip]] package provides functions for 135 extracting a user IP address from a request and associating it with a `Context`. 136 A `Context` provides a key-value mapping, where the keys and values are both of 137 type `interface{}`. 138 Key types must support equality, and values must be safe for simultaneous use by 139 multiple goroutines. 140 Packages like `userip` hide the details of this mapping and provide 141 strongly-typed access to a specific `Context` value. 142 143 To avoid key collisions, `userip` defines an unexported type `key` and uses 144 a value of this type as the context key: 145 146 .code context/userip/userip.go /The key type/,/const userIPKey/ 147 148 `FromRequest` extracts a `userIP` value from an `http.Request`: 149 150 .code context/userip/userip.go /func FromRequest/,/}/ 151 152 `NewContext` returns a new `Context` that carries a provided `userIP` value: 153 154 .code context/userip/userip.go /func NewContext/,/}/ 155 156 `FromContext` extracts a `userIP` from a `Context`: 157 158 .code context/userip/userip.go /func FromContext/,/}/ 159 160 ** Package google 161 162 The [[context/google/google.go][google.Search]] function makes an HTTP request 163 to the [[https://developers.google.com/web-search/docs/][Google Web Search API]] 164 and parses the JSON-encoded result. 165 It accepts a `Context` parameter `ctx` and returns immediately if `ctx.Done` is 166 closed while the request is in flight. 167 168 The Google Web Search API request includes the search query and the user IP as 169 query parameters: 170 171 .code context/google/google.go /func Search/,/q.Encode/ 172 173 `Search` uses a helper function, `httpDo`, to issue the HTTP request and cancel 174 it if `ctx.Done` is closed while the request or response is being processed. 175 `Search` passes a closure to `httpDo` handle the HTTP response: 176 177 .code context/google/google.go /var results/,/return results/ 178 179 The `httpDo` function runs the HTTP request and processes its response in a new 180 goroutine. 181 It cancels the request if `ctx.Done` is closed before the goroutine exits: 182 183 .code context/google/google.go /func httpDo/,/^}/ 184 185 * Adapting code for Contexts 186 187 Many server frameworks provide packages and types for carrying request-scoped 188 values. 189 We can define new implementations of the `Context` interface to bridge between 190 code using existing frameworks and code that expects a `Context` parameter. 191 192 For example, Gorilla's 193 [[http://www.gorillatoolkit.org/pkg/context][github.com/gorilla/context]] 194 package allows handlers to associate data with incoming requests by providing a 195 mapping from HTTP requests to key-value pairs. 196 In [[context/gorilla/gorilla.go][gorilla.go]], we provide a `Context` 197 implementation whose `Value` method returns the values associated with a 198 specific HTTP request in the Gorilla package. 199 200 Other packages have provided cancelation support similar to `Context`. 201 For example, [[http://godoc.org/gopkg.in/tomb.v2][Tomb]] provides a `Kill` 202 method that signals cancelation by closing a `Dying` channel. 203 `Tomb` also provides methods to wait for those goroutines to exit, similar to 204 `sync.WaitGroup`. 205 In [[context/tomb/tomb.go][tomb.go]], we provide a `Context` implementation that 206 is canceled when either its parent `Context` is canceled or a provided `Tomb` is 207 killed. 208 209 * Conclusion 210 211 At Google, we require that Go programmers pass a `Context` parameter as the 212 first argument to every function on the call path between incoming and outgoing 213 requests. 214 This allows Go code developed by many different teams to interoperate well. 215 It provides simple control over timeouts and cancelation and ensures that 216 critical values like security credentials transit Go programs properly. 217 218 Server frameworks that want to build on `Context` should provide implementations 219 of `Context` to bridge between their packages and those that expect a `Context` 220 parameter. 221 Their client libraries would then accept a `Context` from the calling code. 222 By establishing a common interface for request-scoped data and cancelation, 223 `Context` makes it easier for package developers to share code for creating 224 scalable services.