Intro and Practice of Golang Context

Golang Context

Let’s learn how to use the Golang Context and how to implement it in the Standard Library.

The Golang context package started as a Go package used internally by Google and was officially introduced into the Standard Library in Golang version 1.7.

A brief introduction to Golang Contexts

Before learning about context packages, look at several business scenarios that you often encounter in your daily development:

  1. Business needs to have access to databases, RPC s, or API interfaces, and in order to prevent these dependencies from causing our services to time out, time-out controls need to be tailored.
  2. To learn more about service performance, record detailed call chain logs.

These two scenarios are common on the web, and the context package is designed to make it easier for us to use them.

Next, we first learn what methods the context package has for us to use; then, for example, use the context package application to solve the problems we encounter in the scenarios above; and finally, from the source point of view, learn the internal implementation of the context to understand how it works.

The Golang Context Package

Context Definition

Many Context objects are implemented in the context package.Context is an interface that describes the context of a program.Four abstract methods are provided in the interface, defined as follows:

type Context interface {
  Deadline() (deadline time.Time, ok bool)
  Done() <-chan struct{}
  Err() error
  Value(key interface{}) interface{}
}
  • Deadline() returns the end time of the context, ok is false if not set
  • Done() When the context of execution is cancelled, chan Chan returned by Done is close d.If this context is not cancelled, return nil
  • Err() has several cases:
    • If Done() returns chan without closing, returns nil
    • If chan returned by Done() is closed, Err returns a non-nil value explaining why Done()
      • If Canceled, return to Canceled
      • If Deadline is exceeded, return “Deadline Esceeded”
  • Value(key) returns the value corresponding to the key in the context

Context Construction

To use a Context, we need to understand how it is constructed.

Context provides two methods to initialize:

func Background() Context{}
func TODO() Context {}

The above methods all return an empty Context, but Background is generally the basis of all Contexts, and the source of all Contexts should be it.The TODO method is typically used to avoid a Context initialized with a nil parameter when the incoming method is not sure what type of Context it is.

Other ontexts are implemented based on already constructed contexts.A Context can derive multiple child contexts.The methods to derive a new Context based on ontext are as follows:

func WithCancel(parent Context) (ctx Context, cancel CancelFunc){}
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) {}
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {}

The three methods above are similar, generating a child ctx and a Cancel method based on the parent Context.If the cancel method is called, both ctx and a child context constructed from ctx are canceled.The difference is that WithCancel must call the cancel method manually, WithDeadline
You can set a point in time, WithTimeout is to set the duration of the call, after which cancel is called to cancel.

In addition to the above constructs, contexts are also used to create essential data such as traceId, token, etc.

func WithValue(parent Context, key, val interface{}) Context {}

withValue constructs a new context, which contains a pair of Key-Value data you can use to get the value in ctx from Context.Value(Key).

From this understanding, it is possible to conclude that a Context is a tree structure and that a Context can derive from many different Contexts.We can probably draw a tree like this:

A background, derives a valueCtx with traceId, and then valueCtx derives a cancelCtx with cancelCtx
context of.Finally, some db queries, http queries, rpc Sasson and other asynchronous calls are reflected.If time-outs occur, cancel these asynchronous calls directly to reduce resource consumption, we can also get the traceId through the Value method and record the data for the corresponding request at the time of the call.

Of course, in addition to the several Contexts above, we can implement a new Context based on the ontext interface above.

Usage method of the Golang Context Package

Let’s take a few examples to learn the above methods.