Golang context

2016-08-08

The upcoming release of Go 1.7 shall move the golang.org/x/net/context package into the standard library. The move standardizes a simple interface and several simple functions that allow for straightforward concurrent processing as detailed in a 2014 Go blog post. More importantly a Context can be attached *http.Request allowing for cleaner and more concise code.

An example is a recurring pattern used in middleware or http handler processing that looks a little bit like:

More importantly it’s not clear that ctx is associated with r and that the values within ctx or functionality shall affect the request or processing. For example:

vs

Attaching context to a request leads to code that is easier to understand and maintain. With that aside let’s have some fun with context, requests, and concurrency.

Note: There’s plenty of code left out to make the following fully functional. The code is meant to get an idea across rather than as a functional example or even a guideline.

When processing requests getting a response to the requestor quickly should be a high, if not the highest, priority. Many times middleware processing delays a response by serially processing headers or processing authentication tokens. The typical handler flow looks like:

  1. Receive request
  2. Process cookie or auth token, create new context.WithValue
  3. Parse request, read values from context, process request, write response
  4. Write to log

The handler for step 2 may look like:

Pretty straightforward and typical to almost all requests (you may also have CORS, rate limiting, etc.) and almost always run serially. Step 2 may involve database operations or network activity that blocks step 3 from parsing the request prior to reading values. We can potentially reduce the time to response by continuing processing while we’re fetching the entity:

In the above we start a goroutine to get the entity while sending the request onwards for processing. If and when the entity value is needed FromContext shall block until the Entity has been retrieved; this may result in an immediate return if the Entity has already been returned. If the value is not needed then everything cleans itself up on the next garbage collector cycle.

The above is a toy example and an interesting thought. If you were to use a pattern like this then it’s worth investing in benchmarking and testing under realistic loads before you start down this route.