進行中の操作のキャンセル

Goのcontext.Contextを使用することで、進行中の操作を管理できます。Contextは、それが表す全体的な操作がキャンセルされ、不要になったかどうかを報告できる標準的なGoのデータ値です。アプリケーション内の関数呼び出しやサービス間でcontext.Contextを渡すことで、処理が不要になった場合に早期に作業を停止してエラーを返すことができます。Contextの詳細については、Goの並行処理パターン: Contextを参照してください。

たとえば、次のことを行うことができます。

Go開発者向けの多くのAPIには、Context引数を受け取るメソッドが含まれており、アプリケーション全体でContextを簡単に使用できます。

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

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

次のタイムアウトの例のコードでは、Contextを派生させ、それをsql.DBQueryContextメソッドに渡しています。

func QueryWithTimeout(ctx context.Context) {
    // Create a Context with a timeout.
    queryCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
    defer cancel()

    // Pass the timeout Context with a query.
    rows, err := db.QueryContext(queryCtx, "SELECT * FROM album")
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()

    // Handle returned rows.
}

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

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