タイムアウト後のデータベース操作のキャンセル

操作がキャンセルされるタイムアウトまたは期限を設定するために、Contextを使用できます。タイムアウトまたは期限付きのContextを導出するには、context.WithTimeoutまたはcontext.WithDeadlineを呼び出します。

以下のタイムアウト例のコードは、Contextを導出し、それをsql.DBQueryContextメソッドに渡します。

  1. func QueryWithTimeout(ctx context.Context) {
  2. // Create a Context with a timeout.
  3. queryCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
  4. defer cancel()
  5. // Pass the timeout Context with a query.
  6. rows, err := db.QueryContext(queryCtx, "SELECT * FROM album")
  7. if err != nil {
  8. log.Fatal(err)
  9. }
  10. defer rows.Close()
  11. // Handle returned rows.
  12. }

この例では、queryCtxctxから導出されるように、外部コンテキストから導出された場合、外部コンテキストがキャンセルされると、導出されたコンテキストも自動的にキャンセルされます。たとえば、HTTPサーバーでは、http.Request.Contextメソッドはリクエストに関連付けられたコンテキストを返します。そのコンテキストは、HTTPクライアントが切断するか、HTTPリクエストをキャンセルすると(HTTP/2で可能)、キャンセルされます。上記のQueryWithTimeoutにHTTPリクエストのコンテキストを渡すと、全体のHTTPリクエストがキャンセルされた場合、またはクエリが5秒以上かかった場合に、データベースクエリが早期に停止します。

注意: タイムアウトまたは期限付きの新しいContextを作成するときに返されるcancel関数の呼び出しは常に遅延させてください。これにより、含まれる関数が終了するときに新しいContextが保持しているリソースが解放されます。また、queryCtxもキャンセルされますが、関数が戻る時点でqueryCtxを使用しているものは何もないはずです。