其他
Go 中设计或调试 context.Context…
适用于 Go 项目需要正确传播 context、处理取消/超时/截止时间、存取请求作用域值,以及让后台工作超出生请求的场景。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 48/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 55/100 ×0.15
适用场景
Go 中设计或调试 context.Co通用
解决思路
- 在整个请求生命周期传播同一个 context:HTTP handler → service → DB → 外部 API;任何环节新建 context 都会让客户端断开后继续工作。
- 将 `ctx` 作为第一个参数,命名为 `ctx context.Context`;固定位置让 context-aware API 一眼可辨,也便于 linter 检查。
- 通过函数参数传递 context,不要存储在 struct 中;struct 的生命周期长于填充它的请求,后续调用会复用已取消或属于他人的 context。
- 传递 `context.TODO()` 而不是 `nil` context;`nil` 会在第一次调用 `Done()` 或 `Value()` 时 panic,且远离传入它的调用方。
- 对 `WithCancel`/`WithTimeout`/`WithDeadline` 在所有控制流路径调用 `cancel()`,除非明确返回或转移 context 与 cancel 函数的所有权;未调用的 `cancel()` 会让子 context 保持挂接父 context 并泄漏其 timer,直到父 context 结束。
- 只在顶层入口点(main、init、测试)创建 `context.Background()`;更深调用链中——尤其是请求中途——它会将工作从调用方的 deadline 和取消中分离。
- 当需要 context 但尚不存在时,用 `context.TODO()` 占位;它标记缺口以便后续修复,而不是用看起来刻意的 `Background()` 隐藏它。
- 将 context value 的 key 声明为未导出类型;如果使用普通 `string` key,两个包都使用 “user” 时会静默互相覆盖。
- 只在 context values 中携带请求作用域元数据,绝不携带函数参数;通过 `Value()` 取出的值丢失编译期类型,并从函数签名中消失。
- 当启动必须比父请求存活更久的后台工作时,使用 `context.WithoutCancel`(Go 1.21+);否则 handler 返回会取消刚开始的审计日志或清理工作。
- 创建 context 时按场景选择:入口点(main、init、测试)用 `context.Background()`。
- 创建 context 时按场景选择:函数需要 context 但调用方尚未提供时用 `context.TODO()`。
- 创建 context 时按场景选择:HTTP handler 内用 `r.Context()`。
- 创建 context 时按场景选择:需要取消控制时用 `context.WithCancel(parentCtx)`。
- 创建 context 时按场景选择:需要 deadline/timeout 时用 `context.WithTimeout(parentCtx, duration)`。
- 传播同一个 context 贯穿完整调用链:不要在 `ExecContext` 等下游调用中传 `context.Background()`,而应传 `ctx`;正确传播时取消父 context 会自动取消所有下游工作。
- 取消/超时/截止:`WithCancel` 用于手动取消,`WithTimeout` 用于持续时间后自动取消,`WithDeadline` 用于绝对时间截止。
- 在并发代码中监听 `<-ctx.Done()`。
- 使用 `AfterFunc` 回调处理取消/超时相关逻辑。
- 对必须比父请求存活更久的操作(如审计日志)使用 `WithoutCancel`。
- 用未导出 key 类型防止 context value 命名空间冲突。
- context values 用于请求 ID、用户 ID 等请求作用域元数据,而不是函数参数。
- 传播 OpenTelemetry trace headers、用于日志聚合的 correlation IDs,并跨服务边界 marshal/unmarshal context。
- HTTP handler context:用 `r.Context()` 进行请求作用域取消,集成 middleware,并传播到 services。
- HTTP client:用 `NewRequestWithContext`,设置 client timeouts,并进行 context-aware retries。
- 数据库操作:始终用 `*Context` 变体(`QueryContext`、`ExecContext`)以遵守 deadlines。
- 许多 context 陷阱可由 `govet`、`staticcheck` 自动捕获;参考 `golang-lint` skill 进行配置和使用。
适用边界 · 注意事项
- 不适用于代码仅仅接受 `ctx` 作为第一个参数、但不涉及 context 传播、取消、超时/截止时间、请求作用域值或后台任务设计的场景。
- 不适用于非 Go 项目或不需要 `context.Context` 的代码。
- 如果公司技能明确取代 `samber/cc-skills-golang@golang-context`,应优先使用公司技能。