Go Context Cancellation
Context cancellation is a way to tell running work to stop through a shared signal. The signal travels inside a context value from one function to the next.
Cancel closes Done and sets Err
WithCancel builds the context and hands back a cancel function. One call closes Done and sets the error.
package main
import (
"context"
"fmt"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
cancel()
<-ctx.Done()
fmt.Println(ctx.Err())
fmt.Println(ctx.Err() == context.Canceled)
}A worker stops when Done closes
The worker signals that it started, then waits in a select on Done. Main cancels after the signal and joins the worker before printing.
package main
import (
"context"
"fmt"
"sync"
)
func worker(ctx context.Context, started chan struct{}, wg *sync.WaitGroup) {
defer wg.Done()
close(started)
select {
case <-ctx.Done():
fmt.Println("Worker stopped.")
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
started := make(chan struct{})
var wg sync.WaitGroup
wg.Add(1)
go worker(ctx, started, &wg)
<-started
cancel()
wg.Wait()
fmt.Println("Main finished.")
}One context passes through two functions
First hands the context to second without changing it. The cancel made in main still reaches the bottom call.
package main
import (
"context"
"fmt"
)
func second(ctx context.Context) {
<-ctx.Done()
fmt.Println("Second:", ctx.Err())
}
func first(ctx context.Context) {
second(ctx)
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
cancel()
first(ctx)
fmt.Println("Main finished.")
}Example
package main
import (
"context"
"fmt"
"sync"
)
func stageOne(out chan<- string) {
out <- "Stage one done"
}
func stageTwo(ctx context.Context, wg *sync.WaitGroup) {
defer wg.Done()
<-ctx.Done()
fmt.Println("Stage two stopped:", ctx.Err())
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
out := make(chan string)
var wg sync.WaitGroup
wg.Add(1)
go stageTwo(ctx, &wg)
go stageOne(out)
fmt.Println(<-out)
cancel()
wg.Wait()
fmt.Println("Main finished.")
}Key points
- A context is a value that carries a stop signal through a program.
- Use context.WithCancel to build a context that code can cancel by hand.
- WithCancel returns the context and a cancel function.
- Calling the cancel function closes the Done channel of the context.
- The Err method of a cancelled context returns context.Canceled.
- A worker can wait on Done inside a select statement.
In this example, main starts a second stage that waits on the Done channel. The first stage hands its line to main through a channel, and main prints it. Main then cancels the context, so the second stage prints its stopped line. The WaitGroup join keeps the main line last.
Note
Calling the cancel function more than once is safe.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Go Playground
Exercise
What happens when the cancel function of a context is called?