在 Golang 中慣用地使用 context.Context — 透過 API 邊界傳播、取消、逾時與截止時間、請求範圍的值、以及 context.WithoutCancel 用於超出請求生命週期的背景工作。適用於設計跨層級的 context 傳播、偵測洩漏或未過期的 context、選擇 context.Background/TODO/WithoutCancel,或在 context 中儲存值。不適用於僅將 ctx 作為第一個參數的程式碼。
社群預設。 若公司技能明確取代
samber/cc-skills-golang@golang-context技能,則以公司技能為準。
Go context.Context 最佳實務
context.Context 是 Go 用來在 API 邊界與 goroutine 之間傳遞取消訊號、截止時間以及請求範圍值的機制。可以把它想像成請求的「工作階段」——它將屬於同一個工作單元的所有操作串聯在一起。
最佳實務摘要
- 同一個 context 必須在整個請求生命週期中傳播:HTTP handler → service → DB → 外部 API
ctx必須是第一個參數,命名為ctx context.Context- 絕對不要將 context 儲存在 struct 中——應透過函式參數明確傳遞
- 絕對不要傳遞
nilcontext——如果不確定,請使用context.TODO() - 對於
WithCancel/WithTimeout/WithDeadline,必須在所有控制流程路徑上呼叫cancel(),除非明確回傳或轉移 context 與 cancel 函式的所有權 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 handler 內部 | r.Context() |
| 需要取消控制 | context.WithCancel(parentCtx) |
| 需要截止時間/逾時 | context.WithTimeout(parentCtx, duration) |
Context 傳播:核心原則
最重要的規則:在同一個呼叫鏈中傳遞同一個 context。當你正確傳播時,取消父 context 會自動取消所有下游工作。
// ✗ 不好——建立新的 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)與函式參數。追蹤 context 傳播:OpenTelemetry 追蹤標頭、用於日誌聚合的關聯 ID,以及在服務邊界之間序列化/反序列化 context。
-
HTTP 伺服器與服務呼叫中的 Context — HTTP handler context:
r.Context()用於請求範圍的取消、中介軟體整合,以及傳播到服務。HTTP 客戶端模式:NewRequestWithContext、客戶端逾時,以及具 context 感知的重試。資料庫操作:一律使用*Context變體(QueryContext、ExecContext)以遵守截止時間。
交叉參考
- → 參閱
samber/cc-skills-golang@golang-concurrency技能,了解使用 context 的 goroutine 取消模式 - → 參閱
samber/cc-skills-golang@golang-database技能,了解具 context 感知的資料庫操作(QueryContext、ExecContext) - → 參閱
samber/cc-skills-golang@golang-observability技能,了解使用 OpenTelemetry 的追蹤 context 傳播 - → 參閱
samber/cc-skills-golang@golang-design-patterns技能,了解逾時與韌性模式
使用 Linter 強制執行
許多 context 陷阱可由 linter 自動偵測:govet、staticcheck。→ 參閱 samber/cc-skills-golang@golang-lint 技能以了解設定與使用方式。






