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.
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.