進行中の操作のキャンセル
Goのcontext.Context
を使用することで、進行中の操作を管理できます。Context
は、それが表す全体的な操作がキャンセルされ、不要になったかどうかを報告できる標準的なGoのデータ値です。アプリケーション内の関数呼び出しやサービス間でcontext.Context
を渡すことで、処理が不要になった場合に早期に作業を停止してエラーを返すことができます。Context
の詳細については、Goの並行処理パターン: Contextを参照してください。
たとえば、次のことを行うことができます。
- 完了までに時間がかかりすぎるデータベース操作など、実行時間の長い操作を終了します。
- クライアントが接続を閉じた場合など、他の場所からのキャンセル要求を伝播します。
Go開発者向けの多くのAPIには、Context
引数を受け取るメソッドが含まれており、アプリケーション全体でContext
を簡単に使用できます。
タイムアウト後のデータベース操作のキャンセル
Context
を使用して、操作がキャンセルされるまでのタイムアウトまたは期限を設定できます。タイムアウトまたは期限付きのContext
を派生させるには、context.WithTimeout
またはcontext.WithDeadline
を呼び出します。
次のタイムアウトの例のコードでは、Context
を派生させ、それをsql.DB
のQueryContext
メソッドに渡しています。
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.
}
この例では、queryCtx
がctx
から派生しているように、あるコンテキストが外側のコンテキストから派生している場合、外側のコンテキストがキャンセルされると、派生したコンテキストも自動的にキャンセルされます。たとえば、HTTPサーバーでは、http.Request.Context
メソッドはリクエストに関連付けられたコンテキストを返します。HTTPクライアントが切断するか、HTTPリクエストをキャンセルすると(HTTP/2で可能)、そのコンテキストはキャンセルされます。上記のQueryWithTimeout
にHTTPリクエストのコンテキストを渡すと、全体的なHTTPリクエストがキャンセルされた場合、またはクエリに5秒以上かかった場合のいずれかで、データベースクエリが早期に停止します。
注意: タイムアウトまたは期限付きで新しいContext
を作成するときに返されるcancel
関数への呼び出しは、常にdeferしてください。これにより、包含する関数が終了したときに、新しいContext
が保持しているリソースが解放されます。また、queryCtx
もキャンセルされますが、関数が返される頃には、queryCtx
を使用しているものは何もなくなっているはずです。