0
0
GoHow-ToBeginner · 3 min read

How to Use Context for Cancellation in Go: Simple Guide

In Go, use the context package to manage cancellation by creating a cancellable context with context.WithCancel. Pass this context to goroutines or functions, and call the cancel function to stop work early, which they detect by checking ctx.Done().
📐

Syntax

The basic pattern for cancellation uses context.WithCancel(parentContext), which returns a new context and a cancel function. You pass the new context to your goroutines or functions. When you want to stop the work, call the cancel function. The goroutines listen for cancellation by checking the ctx.Done() channel.

  • parentContext: Usually context.Background() or another context.
  • ctx: The new cancellable context.
  • cancel: Function to call to cancel the context.
  • ctx.Done(): Channel closed when cancellation happens.
go
ctx, cancel := context.WithCancel(context.Background())
// pass ctx to goroutines
// call cancel() to stop
select {
case <-ctx.Done():
    // handle cancellation
}
💻

Example

This example shows a goroutine that prints numbers every second. The main function cancels the context after 3 seconds, stopping the goroutine cleanly.

go
package main

import (
	"context"
	"fmt"
	"time"
)

func printNumbers(ctx context.Context) {
	i := 1
	for {
		select {
		case <-ctx.Done():
			fmt.Println("Cancelled, stopping printNumbers")
			return
		default:
			fmt.Println(i)
			i++
			time.Sleep(1 * time.Second)
		}
	}
}

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	go printNumbers(ctx)

	time.Sleep(3 * time.Second)
	cancel() // stop the goroutine

	// wait a bit to see cancellation message
	time.Sleep(1 * time.Second)
}
Output
1 2 3 Cancelled, stopping printNumbers
⚠️

Common Pitfalls

Common mistakes include:

  • Not passing the context to all goroutines or functions that need cancellation.
  • Forgetting to call the cancel function, which can cause resource leaks.
  • Ignoring the ctx.Done() channel, so goroutines never stop.
  • Using context.Background() directly inside goroutines instead of passing the cancellable context.

Always ensure you call the cancel function and check ctx.Done() properly.

go
/* Wrong way: ignoring cancellation */
func work() {
	for {
		// no ctx, no cancellation check
		fmt.Println("Working...")
		time.Sleep(1 * time.Second)
	}
}

/* Right way: use context and check ctx.Done() */
func work(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			return
		default:
			fmt.Println("Working...")
			time.Sleep(1 * time.Second)
		}
	}
}
📊

Quick Reference

Remember these key points when using context for cancellation:

  • Use context.WithCancel(parent) to create a cancellable context.
  • Pass the context to all functions and goroutines that should stop on cancellation.
  • Call the cancel function to signal cancellation.
  • Check ctx.Done() channel to detect cancellation and stop work.
  • Always call cancel to avoid resource leaks.

Key Takeaways

Use context.WithCancel to create a cancellable context and get a cancel function.
Pass the cancellable context to all goroutines or functions that need to stop early.
Call the cancel function to signal cancellation and have goroutines listen on ctx.Done().
Always check ctx.Done() in select statements to handle cancellation properly.
Remember to call cancel to avoid resource leaks and clean up resources.