Go Context
Use context.Context to carry cancellation, deadlines, and request-scoped metadata across API boundaries. It is not a dependency container or a substitute for ordinary parameters.
Inspect the lifecycle
Before editing, trace the unit of work from its owner to every downstream call:
- Where is the root context created?
- Which caller owns cancellation and the deadline budget?
- Which calls can block, spawn work, or cross a process boundary?
- Does any child intentionally outlive its parent, and who owns that child?
- Which values are genuinely request-scoped and cross-cutting?
Read repository conventions and the minimum Go version in go.mod. Preserve established API contracts unless changing them is part of the request.
API rules
- Accept
ctx context.Contextas the first parameter of functions whose work can be cancelled or carries request metadata. Do not add context to pure, immediate helpers without a lifecycle need. - Pass the caller's context downstream rather than replacing it with
Backgroundin the middle of the call chain. - Do not pass
nil; use a real parent orcontext.TODO()only as a visible temporary migration marker. - Prefer passing context per operation rather than storing it in a long-lived struct. A struct representing one operation may legitimately contain it when that API's documented lifecycle requires it.
- Call a returned cancel function on every path once the derived context is no longer needed, unless ownership of cancellation is explicitly transferred.
- A child cannot extend its parent's deadline. Before adding nested timeouts, decide which layer owns the budget and whether the shorter deadline is intentional.
For cancellation, detached work, causes, and callbacks, read cancellation and deadlines.
Boundary propagation
Use context-aware APIs for outbound HTTP, database, RPC, and other blocking calls. A client-wide timeout and a request context solve different problems; keep both when both policies matter. See HTTP and service boundaries.
Values
Use context values only for request-scoped metadata that must cross API boundaries without becoming a business parameter, such as trace state or a request ID. Define typed, package-owned accessors and avoid built-in string keys. See values and tracing.
Review checklist
- Cancellation can reach every blocking stage that should stop.
- Long loops or channel operations observe cancellation at useful interruption points.
- Derived contexts release timers and references promptly.
- Detached work has its own owner, timeout, error handling, and shutdown path.
- Retries stop when the context is done and do not silently reset the caller's budget.
- Returned errors preserve the distinction between cancellation, deadline expiry, and an operation failure when callers rely on it.
Run focused tests through the project's existing commands. Prefer deterministic cancellation tests using channels or barriers over timing-only sleeps.