
2 min read
Context deadlines
On Friday we looked at the context.Context interface as a whole. Now let’s go back and look at each method in greater detail. type Context type Context interface { // Deadline returns the time when work done on behalf of this context // should be canceled. Deadline returns ok==false when no deadline is // set. Successive calls to Deadline return the same results. Deadline() (deadline time.Time, ok bool) So there are two general cases here:

2 min read
The Context API contract
Today we come to the core of the context package: The Context interface itself. type Context type Context interface { Deadline() (deadline time.Time, ok bool) Done() <-chan struct{} Err() error Value(key any) any } A Context carries a deadline, a cancellation signal, and other values across API boundaries. Context’s methods may be called by multiple goroutines simultaneously. For clarity, I’ve removed all of the documentation for each of the interface methods in the above quote—we’ll get to those in following emails, and include those there.

2 min read
Contexts with timeouts
func WithTimeout func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). Canceling this context releases resources associated with it, so code should call cancel as soon as the operations running in this Context complete: func slowOperationWithTimeout(ctx context.Context) (Result, error) { ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) defer cancel() // releases resources if slowOperation completes before timeout elapses return slowOperation(ctx) } Not only is WithTimeout conceptually similar to WithDeadline, it literally is WithDeadline, as we can see form the source code:

2 min read
Contexts with deadlines
Today we’re talking about canceling contexts based on time. Arguably, this should have come first, as it’s a little simpler to work with than the explicit cancelation we talked about a week ago. But once again, I’m going in essentially alphabetical order, so it’s what we have… func WithDeadline func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) WithDeadline returns a derived context that points to the parent context but has the deadline adjusted to be no later than d.
Subscribe to Boldly Go: Daily
Every day I'll send you advice to improve your understanding of Go. Don't miss out! I will respect your inbox, and honor my privacy policy.
Unsure? Browse the archive.

2 min read
Context causes
About a week ago, I talked about the two error types that a context may return: context.Canceled and context.DeadlineExceeded. But what if you want to convey some other error? Maybe you want to distinguish between a context that was canceled because the server is shutting down due to a SIGINT, versus becasue the request was canceled by the client, for example? Enter Cause. func Cause func Cause(c Context) error Cause returns a non-nil error explaining why c was canceled.

2 min read
Canceling a context
I’m jumping out of order a bit today, to cover a more basic function first, before the more advanced version. Bear with me. func WithCancel func WithCancel(parent Context) (ctx Context, cancel CancelFunc) WithCancel returns a derived context that points to the parent context but has a new Done channel. The returned context’s Done channel is closed when the returned cancel function is called or when the parent context’s Done channel is closed, whichever happens first.

2 min read
AfterFunc
One of the drawbacks of this format I’ve chosen—reading through a document, and providing commentaty, in order—is that sometimes advanced topics come up before the foundational ones they rely on. Today is one such case. Typically, context cancelation is used to terminate an action in progress. But it can also be used to begin an action. One way to accomplish this is to wait for a cancelation signal in a goroutine:

1 min read
Context package variables
The context package exports two variables: Variables var Canceled = errors.New("context canceled") Canceled is the error returned by [Context.Err] when the context is canceled for some reason other than its deadline passing. var DeadlineExceeded error = deadlineExceededError{} DeadlineExceeded is the error returned by [Context.Err] when the context is canceled due to its deadline passing. That’s it. These are the only two types of errors that a context’s Err() method is allowed to return.

2 min read
Concurrent use of contexts
Overview … The same Context may be passed to functions running in different goroutines; Contexts are safe for simultaneous use by multiple goroutines. Contexts are built using layers. Every time you call one of the context.With* functions, the orginal context is wrapped in a new layer. This is the “magic” that makes contexts concurrency safe by design–they’re never mutated once they’re created. ctx := context.Background() // Create an original context ctx, cancel = context.

2 min read
When not to use context values
Storing values in a context is quite flexible, but comes without strict type safety, and obscures the API. So what can we do about this? First, for type safety, we’re limited to runtime assertions: userID := ctx.Value(userIDKey).(string) But this can panic if we ever get an unexpected value (or even nil). So to make it safer, we can use the two-variable assignment form, which yields a bool indicating success: userID, ok := ctx.

2 min read
Context values and type safety
Last week I asked whether or not it’s a good idea to pass things like a user-scoped database handle or logger via a context value. Before I provide my direct answer, I want to take a short detour… Go is a (mostly) strictly-typed language. This gives us certain guarantees. When we have a variable of type int, we know it doesn’t contain the value "cow", because that’s not an integer.