在Golang中用上下文WithTimeout和WithCancel取消数据库查询

218 阅读1分钟

我们将通过使用下面列出的两种情况来停止所有活动查询:

  • 如果查询的时间超过5秒
    • 这将是使用WithTimeout 功能的子环境的责任。查询将停止并产生context deadline exceeded 错误。
  • 如果应用程序崩溃/停止/取消(无论查询运行了多长时间)
    • 这将是父语境的责任,它使用了WithCancel 的功能。查询将停止,并产生context canceled 的错误。

如上所述,我们有一个用于整个应用程序的父上下文和一个从父上下文派生的子上下文。结果是。

  • 如果子上下文被取消,只有与之相连的操作受到影响。父上下文保持不变。

  • 如果父上下文被取消,所有与之相连的操作都会受到影响。这也包括所有派生的子上下文。从技术上讲,整个应用程序都会受到影响。

例子

我们将我们的父上下文设置为HTTP服务器的BaseContext ,因此它在整个请求范围内对我们是可用的。

func main() {
    // Parent context.
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

    srv := &http.Server{
		Addr:    "some-address",
		Handler: "some-handler",
		BaseContext: func(listener net.Listener) context.Context {
			return ctx
		},
	}

    // ...
}

请确保你从HTTP请求中获取父上下文,并将其注入到你运行查询的地方。目前,我在处理程序中做了一切:

func myHandler(w http.ResponseWriter, r *http.Request) {
    // Grab the parent context.
    ctx := r.Context()
    
    // Create child context derived from the parent context.
    ctx, cancel := context.WithTimeout(ctx, 5 * time.Second)
    defer cancel()

    // Link the child context to the query.
    rows, err := DB.QueryContext(ctx, `some query`)
    // ...
}