contextパッケージは、特にgoroutineや外部呼び出し(HTTP、DB)でコードの部分間でメタデータを渡すためのライフサイクル管理(キャンセル、タイムアウト)の標準です。
作成方法:
リソースを正しく解放するためにコンテキストを終了させることが重要です。例:
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() // その後、ctxはgoroutine/HTTPリクエストで使用される
典型的なパターンは、関数の最初の引数としてcontextを渡すことです。例:
func process(ctx context.Context) error { ... }
context.TODO()やcontext.Background()を実際のcontextの代わりに渡すことができるのはいつで、2つの違いは何ですか?
多くの人がcontext.Background()をプレースホルダーとして使用します。しかし:
context.Background()はツリーのルートであり、main()やテストでのみ使用し、コンテキストの「ツリー」を初期化する際にのみ使用すべきです。context.TODO()は、どのようなコンテキストが必要かがまだ不明な場合に必要です。リファクタリング時の一時的な「穴埋め」として使用されます。本番コードではTODOは受け入れられません。何がどこに渡されているかを正確に把握する必要があります。物語
マイクロサービスでcontext.WithTimeout()作成後にcancel()を呼び出すのを忘れたため、リクエストが停止し、完了したgoroutineがランタイムに「ぶら下がった」タイマーを残し、メモリリークを引き起こしました。
物語
ハンドラーでリクエストから来たcontextの代わりにcontext.Background()を渡したため、キャンセルチェーンとtrace-idが失われ、タイムアウトの制限が機能せず、リクエストのキャンセルが発動しませんでした。
物語
context.WithValue()を介して開発者がデータを渡しましたが、キーが文字列でした。その結果、異なるパッケージからのキーの衝突により予期しないエラー(「キーはすでに占有されています」)が発生しました。正しいプラクティスは、キーのためにユニークな型を使用することです。