Community default. A company skill that explicitly supersedes samber/cc-skills-golang@golang-context skill takes precedence.
Go context.Context Best Practices
INLINECODE1 is Go's mechanism for propagating cancellation signals, deadlines, and request-scoped values across API boundaries and between goroutines. Think of it as the "session" of a request — it ties together every operation that belongs to the same unit of work.
Best Practices Summary
- 1. The same context MUST be propagated through the entire request lifecycle: HTTP handler → service → DB → external APIs
- INLINECODE2 MUST be the first parameter, named INLINECODE3
- NEVER store context in a struct — pass explicitly through function parameters
- NEVER pass
nil context — use context.TODO() if unsure - INLINECODE6 MUST always be deferred immediately after
WithCancel/WithTimeout/ INLINECODE9 - INLINECODE10 MUST only be used at the top level (main, init, tests)
- Use
context.TODO() as a placeholder when you know a context is needed but don't have one yet - NEVER create a new
context.Background() in the middle of a request path - Context value keys MUST be unexported types to prevent collisions
- Context values MUST only carry request-scoped metadata — NEVER function parameters
- Use
context.WithoutCancel (Go 1.21+) when spawning background work that must outlive the parent request
Creating Contexts
| Situation | Use |
|---|
| Entry point (main, init, test) | INLINECODE14 |
| Function needs context but caller doesn't provide one yet |
context.TODO() |
| Inside an HTTP handler |
r.Context() |
| Need cancellation control |
context.WithCancel(parentCtx) |
| Need a deadline/timeout |
context.WithTimeout(parentCtx, duration) |
Context Propagation: The Core Principle
The most important rule: propagate the same context through the entire call chain. When you propagate correctly, cancelling the parent context cancels all downstream work automatically.
CODEBLOCK0
Deep Dives
- - Cancellation, Timeouts & Deadlines — How cancellation propagates:
WithCancel for manual cancellation, WithTimeout for automatic cancellation after a duration, WithDeadline for absolute time deadlines. Patterns for listening (<-ctx.Done()) in concurrent code, AfterFunc callbacks, and WithoutCancel for operations that must outlive their parent request (e.g., audit logs).
- - Context Values & Cross-Service Tracing — Safe context value patterns: unexported key types to prevent namespace collisions, when to use context values (request ID, user ID) vs function parameters. Trace context propagation: OpenTelemetry trace headers, correlation IDs for log aggregation, and marshaling/unmarshaling context across service boundaries.
- - Context in HTTP Servers & Service Calls — HTTP handler context:
r.Context() for request-scoped cancellation, middleware integration, and propagating to services. HTTP client patterns: NewRequestWithContext, client timeouts, and retries with context awareness. Database operations: always use *Context variants (QueryContext, ExecContext) to respect deadlines.
Cross-References
- - → See the
samber/cc-skills-golang@golang-concurrency skill for goroutine cancellation patterns using context - → See the
samber/cc-skills-golang@golang-database skill for context-aware database operations (QueryContext, ExecContext) - → See the
samber/cc-skills-golang@golang-observability skill for trace context propagation with OpenTelemetry - → See the
samber/cc-skills-golang@golang-design-patterns skill for timeout and resilience patterns
Enforce with Linters
Many context pitfalls are caught automatically by linters: govet, staticcheck. → See the samber/cc-skills-golang@golang-linter skill for configuration and usage.
技能名称: golang-context
详细描述:
社区默认。 一个明确取代 samber/cc-skills-golang@golang-context 技能的公司技能优先。
Go context.Context 最佳实践
context.Context 是Go语言用于在API边界和goroutine之间传播取消信号、截止时间和请求范围值的机制。可以将其视为请求的会话——它将属于同一工作单元的所有操作联系在一起。
最佳实践总结
- 1. 同一个context必须在整个请求生命周期中传播:HTTP处理器 → 服务层 → 数据库 → 外部API
- ctx必须是第一个参数,命名为ctx context.Context
- 永远不要将context存储在结构体中——通过函数参数显式传递
- 永远不要传递nil context——如果不确定,使用context.TODO()
- cancel()必须在WithCancel/WithTimeout/WithDeadline之后立即延迟执行
- context.Background()只能在顶层使用(main、init、测试)
- 使用context.TODO() 作为占位符,当你知道需要context但还没有时
- 永远不要在请求路径中间创建新的context.Background()
- Context值的键必须是未导出的类型,以防止冲突
- Context值只能携带请求范围的元数据——永远不要用作函数参数
- 使用context.WithoutCancel(Go 1.21+)在生成必须比父请求存活更久的后台工作时
创建Context
| 场景 | 使用 |
|---|
| 入口点(main、init、测试) | context.Background() |
| 函数需要context但调用者尚未提供 |
context.TODO() |
| 在HTTP处理器内部 | r.Context() |
| 需要取消控制 | context.WithCancel(parentCtx) |
| 需要截止时间/超时 | context.WithTimeout(parentCtx, duration) |
Context传播:核心原则
最重要的规则:在整个调用链中传播同一个context。当正确传播时,取消父context会自动取消所有下游工作。
go
// ✗ 错误——创建新context,打破链
func (s *OrderService) Create(ctx context.Context, order Order) error {
return s.db.ExecContext(context.Background(), INSERT INTO orders ..., order.ID)
}
// ✓ 正确——传播调用者的context
func (s *OrderService) Create(ctx context.Context, order Order) error {
return s.db.ExecContext(ctx, INSERT INTO orders ..., order.ID)
}
深入探讨
- - 取消、超时和截止时间 — 取消如何传播:WithCancel用于手动取消,WithTimeout用于在持续时间后自动取消,WithDeadline用于绝对时间截止。并发代码中监听(<-ctx.Done())的模式,AfterFunc回调,以及用于必须比父请求存活更久的操作(例如审计日志)的WithoutCancel。
- - Context值和跨服务追踪 — 安全的context值模式:未导出的键类型以防止命名空间冲突,何时使用context值(请求ID、用户ID)与函数参数。追踪上下文传播:OpenTelemetry追踪头、用于日志聚合的关联ID,以及跨服务边界的context序列化/反序列化。
- - HTTP服务器和服务调用中的Context — HTTP处理器context:r.Context()用于请求范围的取消、中间件集成以及传播到服务。HTTP客户端模式:NewRequestWithContext、客户端超时和带有上下文感知的重试。数据库操作:始终使用*Context变体(QueryContext、ExecContext)以遵守截止时间。
交叉引用
- - → 参见samber/cc-skills-golang@golang-concurrency技能,了解使用context的goroutine取消模式
- → 参见samber/cc-skills-golang@golang-database技能,了解上下文感知的数据库操作(QueryContext、ExecContext)
- → 参见samber/cc-skills-golang@golang-observability技能,了解使用OpenTelemetry的追踪上下文传播
- → 参见samber/cc-skills-golang@golang-design-patterns技能,了解超时和弹性模式
使用Linter强制执行
许多context陷阱可以通过linter自动捕获:govet、staticcheck。→ 参见samber/cc-skills-golang@golang-linter技能,了解配置和使用方法。