2 min read
Context values
I’ve already talked a bit about context values, and when not to use them. For a recap, take a look at these previous posts, so I don’t have to rehash those points today: Context abuse Context values and type safety When not to use context values So from here on out, we’re assuming that you have a legitimate reason to store values in a context. How can/should you go about it?
2 min read
Context errors
type Context type Context interface { … // If Done is not yet closed, Err returns nil. // If Done is closed, Err returns a non-nil error explaining why: // DeadlineExceeded if the context's deadline passed, // or Canceled if the context was canceled for some other reason. // After Err returns a non-nil error, successive calls to Err return the same error. Err() error Done() (covered yesterday) and Err() (today) are the two methods you’ll virtually alway use when writing code to honor context cancelations.
5 min read
The Done channel
May I rant for a moment? I don’t like the way GoDoc works for structs and interfaces. And below is a demonstration as to why. It’s not possible to link directly to an interface method or struct field, and the formatting is ugly. sigh type Context type Context interface { … // Done returns a channel that's closed when work done on behalf of this // context should be canceled. Done may return nil if this context can // never be canceled.
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.