Skip to content
Go Basics: Stop a Worker with Context Cancellation

Go Basics: Stop a Worker with Context Cancellation

October 31, 2026

Cancellation is a signal, not proof that a goroutine has stopped. Pair context cancellation with an acknowledgment channel so the caller knows when the worker has observed it.

Prepare a scratch directory

Tested on Linux amd64 with Go 1.26.10. Install Go and make go available on PATH. You also need Bash, a text editor, and the standard mktemp, rm, and rmdir utilities. The example uses only the standard library and needs no module or external dependency.

Keep the same terminal open. Stop if setup fails, before saving the source:

start_dir="$PWD"
work_dir="$(mktemp -d)" || exit 1
cd -- "$work_dir" || exit 1

Run the example

Save this as context-cancellation-demo.go:

package main

import (
	"context"
	"errors"
	"fmt"
)

func main() {
	ctx, cancel := context.WithCancelCause(context.Background())
	defer cancel(nil)
	stopped := make(chan error, 1)
	go func() {
		<-ctx.Done()
		stopped <- context.Cause(ctx)
	}()
	reason := errors.New("batch completed")
	cancel(reason)
	observed := <-stopped
	fmt.Println("Context canceled:", errors.Is(ctx.Err(), context.Canceled))
	fmt.Println("Cause preserved:", errors.Is(observed, reason))
	fmt.Println("Worker acknowledged:", observed)
}

Run it:

go run context-cancellation-demo.go

Observed output:

Context canceled: true
Cause preserved: true
Worker acknowledged: batch completed

Read the result

Cancel closes the context’s Done channel. The worker observes that signal and sends the cause back; receiving the acknowledgment gives the main goroutine a concrete completion point. Err reports the general cancellation state, while Cause retains the application’s explanation.

Apply it carefully

Context does not forcibly interrupt arbitrary code. Real workers must pass context into operations that support it or check Done at sensible boundaries. Always release derived contexts, and do not use a cancellation signal alone as a substitute for waiting for resource cleanup.

The official Go reference documents the behavior used here.

Clean up

Remove the saved source, return to the starting directory, and remove the empty practice directory. go run does not leave an executable here; Go manages its build cache separately.

rm -- context-cancellation-demo.go
cd -- "$start_dir" || exit 1
rmdir -- "$work_dir"
unset start_dir work_dir

If the directory is not empty, inspect its remaining contents before removing anything else.

Acknowledgements

This post was created with assistance from AI.

Last updated on