← Back to Go Course | Chapter 11: Concurrency | Lesson 8 of 8

The context Package

context is like a timer and a stop button you hand to every worker at once, so you can tell them all 'stop now' or youve run out of time' from one place.

Creating a Context with a Timeout

context.WithTimeout creates a context that automatically signals cancellation once the given duration elapses, which is the standard way to bound how long an operation is allowed to run.

Note: Always call the returned cancel function (often via defer) to release the context's resources promptly.

Example: Creating a Context with a Timeout

markup
package main

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

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Millisecond)
	defer cancel()

	select {
	case <-time.After(100 * time.Millisecond):
		fmt.Println("work finished")
	case <-ctx.Done():
		fmt.Println("cancelled:", ctx.Err())
	}
}

Manual Cancellation with WithCancel

context.WithCancel returns a context plus a cancel function that, when called, immediately signals every listener watching ctx.Done(), useful for stopping work in response to some other event, not just a timeout.

Example: Manual Cancellation with WithCancel

markup
package main

import (
	"context"
	"fmt"
)

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

	go func() {
		fmt.Println("cancelling now")
		cancel()
	}()

	<-ctx.Done()
	fmt.Println("received cancellation:", ctx.Err())
}

Passing Context to Functions

Idiomatic Go functions that might need to be cancelled or time out accept a context.Context as their first parameter, letting callers control cancellation without the function needing its own timeout logic baked in.

Note: By convention, ctx is always the first parameter and is never stored inside a struct.

Example: Passing Context to Functions

markup
package main

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

func doWork(ctx context.Context) {
	select {
	case <-time.After(50 * time.Millisecond):
		fmt.Println("work completed")
	case <-ctx.Done():
		fmt.Println("work cancelled:", ctx.Err())
	}
}

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
	defer cancel()
	doWork(ctx)
}
Common Mistakes
  1. Storing a context inside a struct field instead of passing it explicitly as the first parameter of each function, as Go convention expects.
  2. Forgetting to call the cancel function returned by context.WithCancel/WithTimeout, leaking resources associated with the context.
  3. Ignoring ctx.Done() inside a long-running goroutine, so it never actually stops even after the context is cancelled.
Chapter Summary
  • context.Context carries cancellation signals and deadlines across API boundaries and goroutines.
  • context.WithTimeout and context.WithCancel create a derived context plus a cancel function.
  • A goroutine should select on ctx.Done() to notice cancellation and stop its work promptly.
  • Convention: context.Context is passed explicitly as a function's first parameter, named ctx.
🔒

Chapter Quiz — Complete all 8 topics to unlock

0/8 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.