Canceling a context

April 28, 2025

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.

Canceling this context releases resources associated with it, so code should call cancel as soon as the operations running in this Context complete.

Example

WithCancel is the most basic way to extend a context. So it’s a good place to start.

It accepts an existing context, but that may be a background context (i.e. the result of calling context.Background()). It returns a new derivitive context, and a cancel function.

Here’s what it looks like in use:

func doTwoThings(ctx context.Context) {
	ctx, cancel = context.WithCancel(ctx)
	defer cancel

	go func() {
		if err := thingOne(ctx); err !=nil {
			log.Printf("thing one failed: %s", err)
			cancel()
		}
	}()

	go func() {
		if err := thingTwo(ctx); err != nil {
			log.Printf("thing two failed: %w", err)
			cancel()
		}
	}()
}

In this example, we start two goroutines, each listening for cancelation on the same context. Then if either function (thingOne or thingTwo) returns an error, the context is canceled, indicating to the other goroutine that it can abort its work, if it’s still not finished.


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content


Why is context.TODO not just a comment?

I’ve been on vacation for the last week, so haven’t written much. Let’s finally finish up the context package series with some reader feedback and questions! Joost Helberg wrote in with an interesting observation about context.TODO. In his own words: With regards to context.TODO, back in my early Go days, I thought the TODO was about the intent of this context. Like context.Background is for a background task and context.WithCancel for a job that can be canceled.


Context cancelation

As already mentioned, the context.Context type serves two purposes: It manages cancelation signals, and it allows passing request-scoped data. In my opinion, these two purposes are distinct enough that they probably should be handled by two separate mechanisms. But alas, that’s not what we have. However, I think it’s still useful to think of the two uses as distinct. Most often (at least in a well-designed application), the primary purpose of a context is the propegation of cancelation signals.


context.WithValue

func WithValue func WithValue(parent Context, key, val any) Context WithValue returns a derived context that points to the parent Context. In the derived context, the value associated with key is val. Use context Values only for request-scoped data that transits processes and APIs, not for passing optional parameters to functions. The provided key must be comparable and should not be of type string or any other built-in type to avoid collisions between packages using context.

Get daily content like this in your inbox!

Subscribe