context.Context
Intermediate Chapter 3 showed goroutines running independently, with no automatic way for main() to know when they're done short of a channel or WaitGroup. context.Context solves a related but different problem: how does code running several layers deep — goroutines, function calls, network requests — find out that it should stop, because a timeout passed or the caller gave up? There's no real JavaScript equivalent to reach for here; the closest conceptual cousin is an AbortController, but Go's version is used far more pervasively.
The Basic Pattern — Pass ctx as the First Parameter
By strong convention, ctx context.Context is always the first parameter of any function that supports cancellation — never buried among other arguments. ctx.Done() returns a channel (Intermediate Chapter 3) that something closes the moment cancellation happens; select here waits on whichever of two channels is ready first, a new construct specifically for working with multiple channels at once.
context.WithTimeout — Cancel Automatically After a Duration
context.Background() creates a brand-new, empty starting context — the root every other context derives from. context.WithTimeout(parent, duration) wraps it with a deadline: after that duration, ctx.Done() closes automatically, and ctx.Err() reports context deadline exceeded. doWork here finishes via the timeout branch instead of its normal 2-second wait, since the 1-second deadline fires first.
WithTimeout (and its cousin WithCancel) both return a cancel function that must be called to release the context's internal resources, whether or not the timeout ever actually triggers. defer cancel() immediately after creating the context is the standard, safe habit — skipping it can leak resources in long-running programs.
context.WithCancel — Manual Cancellation
WithCancel hands back a cancel function with no automatic timer attached — cancellation happens only when something explicitly calls it, from anywhere that has a reference to that function. This is the pattern used when one part of a program needs to tell every dependent goroutine to stop, on demand, rather than after a fixed duration.
Passing Request-Scoped Values
context.WithValue attaches a single key/value pair to a context, retrievable anywhere downstream via ctx.Value(key) — most commonly used for request-scoped data in a web server (a user ID, a trace ID) that many unrelated layers of code might need without explicitly threading it through every function signature.
WithValue as a way to avoid adding parameters to a function — resist this. It's intended specifically for cross-cutting, request-scoped data (tracing IDs, auth info), not as a general substitute for normal arguments, which stay clearer and more type-safe as actual parameters.
| Tool | Purpose |
|---|---|
| context.Background() | The root context everything else derives from |
| context.WithTimeout(parent, d) | Auto-cancels after duration d; always defer cancel() |
| context.WithCancel(parent) | Manual cancellation via the returned cancel function |
| context.WithValue(parent, key, val) | Attaches request-scoped data, retrieved with ctx.Value(key) |
| ctx.Done() / ctx.Err() | Channel that closes on cancellation; reports why |
Coding Challenges
Write a function countTo(ctx context.Context, n int) that counts from 1 to n, printing each number with a 300ms pause between them, but stops early and prints "Stopped early" if ctx is cancelled. Call it with a context.WithTimeout of 1 second and n = 10, so it stops before reaching 10.
📄 View solutionUsing context.WithCancel, start a goroutine that prints "Working..." every 200ms until cancelled. In main, let it run for about 1 second, then call cancel() and confirm (via a short Sleep and a printed message) that the goroutine stopped.
📄 View solutionDefine a contextKey type and a requestIDKey constant. Use context.WithValue to attach a request ID string to a context, then write a function logRequest(ctx context.Context) that reads it back with ctx.Value and prints it.
📄 View solutionChapter 3 Quick Reference
- ctx context.Context — always the first parameter of a cancellation-aware function
- context.Background() — the root context to start from
- context.WithTimeout(parent, duration) — auto-cancels after a fixed time; always defer cancel()
- context.WithCancel(parent) — manual cancellation via the returned function
- context.WithValue(parent, key, value) — attaches request-scoped data
- ctx.Done() — a channel that closes when the context is cancelled or times out
- ctx.Err() — explains why: context.Canceled or context.DeadlineExceeded
- Next chapter: testing — the testing package, table-driven tests, and go test