Go では、コンテキスト パッケージは、リクエスト スコープのデータ、キャンセル シグナル、タイムアウトや期限をアプリケーションのさまざまなレイヤー間で管理および共有するために設計された基本的なツールです。
context.Context 型は、期限、キャンセル信号、およびその他の要求スコープの値を連鎖可能な階層的な方法で伝達する方法を提供します。これは不変になるように設計されています。つまり、新しい派生コンテキストはそれぞれ、新しい値や動作を追加しながら、親コンテキストのプロパティを引き継ぎます。
コンテキストを、特定のタスクに必要なすべての情報と指示を保持する特別なキャリー バッグとして想像してください。このバッグは機能間で受け渡すことができるため、関係者全員が同じコンテキスト (情報) を持ち、それに応じて行動できるようになります。必要に応じて動作を停止するための自爆ボタン(キャンセル信号)も搭載可能です。
Go に Context が導入される前は、リクエストスコープのデータとキャンセルシグナルの管理は面倒な作業でした。開発者は、関数とゴルーチン間でデータとシグナルを共有するために、カスタム構造体を渡したり、グローバル変数を使用したりするなど、アドホックなソリューションに依存する必要がありました。ただし、これらのアプローチはエラーが発生しやすく、保守が難しく、コンポーネント間の結合が密になることがよくありました。
コンテキストの必要性は、プログラム内の多くの操作が非同期、同時、または外部システムに依存しているという事実から生じます。このような場合、キャンセル信号、期限、リクエストスコープのデータを複数の関数やゴルーチンに伝播する方法が不可欠です。
コンテキストの必要性を説明するために、いくつかのシナリオを考えてみましょう:
あなたがにぎやかなレストランで注文を取る人であると想像してください。注文が届くと、熟練した料理人の 1 人に注文を割り当てます。しかし、顧客が突然退職を決めたらどうなるでしょうか?食材を無駄にしないために、ためらうことなくシェフにその注文の処理を中止するように伝えるでしょう。このシナリオは、Go でコンテキストがどのように機能するかを反映しています。
アプリケーションが外部 API に Web リクエストを行うか、システム コマンドを実行するとします。実稼働グレードのシステムでは、タイムアウトを設定することが不可欠です。その理由は次のとおりです:
API の依存関係: サービスが外部 API に依存していると想像してください。 API の実行が遅い場合、または応答しなくなった場合、保留中のリクエストをシステムにバックアップさせることは望ましくありません。タイムアウトにより、API 呼び出しが指定された時間を超えた場合に、関連付けられたコンテキストがキャンセルされ、アプリケーションが状況を適切に処理できるようになります。
パフォーマンスの低下: タイムアウトなし、外部速度が遅い
依存関係は連鎖的な影響を引き起こす可能性があります。バックログされたリクエストは負荷を増加させ、パフォーマンスを低下させ、システム全体の応答性に影響を与えます。期限のあるコンテキストを使用することで、この問題を防ぐことができます。
Go のコンテキスト パッケージは多用途であり、リクエスト スコープのデータ、キャンセル シグナル、タイムアウトを管理するためにさまざまなシナリオで使用されます。
実際の一般的な使用例をいくつか示します:
1.分散サービス間でのトレース ID の伝播
マイクロサービス アーキテクチャでは、さまざまなサービスにわたるリクエストを追跡することが監視とデバッグに重要です。コンテキスト パッケージを使用すると、サービス境界を越えてトレース ID やその他のメタデータを伝播でき、リクエストのライフサイクル全体を通じて一貫したロギングとトレース情報を確保できます。
2.認証トークンを渡す
多くのアプリケーションでは、認証トークンまたはユーザー情報をアプリケーションのさまざまな層を介して渡す必要があります。コンテキスト パッケージは、これを処理するクリーンな方法を提供し、追加のパラメーターで関数の署名を汚染することなく、必要な場所で認証情報を利用できるようにします。
3. WebSocket とストリーミング API
WebSocket およびストリーミング API では、コンテキストは接続の有効期間を管理し、ユーザー ID やセッション情報などのリクエスト スコープのデータを伝播するために使用されます。これにより、認証、レート制限、セッション管理などの機能を効率的に実装できます。
Go のコンテキスト パッケージは、コンテキスト オブジェクトを作成および操作するためのいくつかの方法を提供します。一般的に使用されるタイプの内訳は次のとおりです:
これは最も基本的なコンテキストであり、空の開始点として機能します。キャンセルのシグナルや期限はありません。特定のコンテキストが必要ない場合に使用します。
バックグラウンドの代わりに TODO が使用されるのは、実装が不明瞭であるか、コンテキストがまだ不明な場合のみです。
通常、main 関数、初期化、テストで使用されます。
ctx := context.Background()
ctx2 := context.TODO()
親コンテキストから派生した新しいコンテキストを作成します。WithCancel メソッドは、キャンセル関数とともに親コンテキストのコピーを返します。 cancel 関数を呼び出すと、コンテキストに接続されているリソースが解放されるため、Context タイプの操作が最終的に完了したらすぐに呼び出す必要があります。
特定の条件が満たされた場合に、ゴルーチン内の操作をキャンセルするために使用されます。
parentCtx := context.Background()
ctx、キャンセル := context.WithCancel(parentCtx)
defer cancel() // リソースをクリーンアップします
自分自身に期限を設定するのと同じように、状況に応じて期限を設定できます。指定した終了時間制限に達すると、Go は自動的にコンテキストをキャンセルします。特定の期限を指定して、親コンテキストから派生した新しいコンテキストを作成します。
操作を完了する特定の期限がある場合に便利です。
parentCtx := context.Background()
期限 := time.Now().Add(10 * time.Second)
ctx、キャンセル := context.WithDeadline(parentCtx, 期限)
defer cancel() // リソースをクリーンアップします
関連するキーと値のペアを使用して、親コンテキストから派生した新しいコンテキストを作成します。これにより、コンテキスト内でリクエスト固有の情報を保存および取得できるようになります。 WithValue は親コンテキストを受け入れ、コンテキストのコピーを返します。その結果、値を上書きするのではなく、新しいキーと値のペアを持つ新しい複製が作成されます。
認証トークンやトレース ID など、リクエストスコープのデータをコンテキスト経由で渡すのに役立ちます。
parentCtx := context.Background()
userIDKey := "認証トークン"
ctx := context.WithValue(parentCtx, userIDKey, "abc123")
タイムアウトが関連付けられたコンテキストを作成します。コンテキストは、指定された期間が経過すると自動的にキャンセルされます。 Timeout を使用すると、プログラムが停止する可能性がある場所で継続できるようになり、エンド ユーザーに優れたエクスペリエンスを提供できます。親コンテキストとともに短い期間をパラメータとして受け取り、タイムアウト期間を超えて実行されると関数を終了します。
操作の期限を設定するのに役立ちます。
parentCtx := context.Background()
ctx、キャンセル := context.WithTimeout(parentCtx, 5*time.Second)
defer cancel() // リソースをクリーンアップします
Go のコンテキストの力について説明したので、次は GoFr が GoFr Context を使用してそれをさらに一歩進める方法について詳しく説明します。
GoFr は、Go 上に構築された独自のマイクロサービス開発フレームワークです。堅牢でスケーラブルなマイクロサービスを構築するための構造化されたアプローチを提供することで、開発プロセスを合理化することを目的としています。
GoFr Context は、標準の Go コンテキスト パッケージの周囲にラッパーを作成することで、その機能を美しく拡張します。このラッパーは、コンテキスト オブジェクトを通じて直接アクセスできる、事前設定された依存関係の豊富なセットを提供します。この完全にロードされたコンテキストにより、開発者は単一のコンテキスト オブジェクトからロギング、データベース接続、基盤となるサービス、トレース、メトリクスのすべてにシームレスにアクセスできるようになります。
func MyHandler(c *gofr.Context) (interface{}, error) { // Logging c.Info("Processing request...") // Database access var value int err := c.SQL.QueryRowContext(c, "select 2+2").Scan(&value) if err != nil { return nil, datasource.ErrorDB{Err: err, Message: "error from sql db"} } // Accessing another service resp, err := c.GetHTTPService("anotherService").Get(c, "book", nil) if err != nil { return nil, err } // Creating a tracing span span := c.Trace("some-sample-work") defer span.End() // ... perform some work return value, nil }
この例では、GoFr Context オブジェクトを通じてログ記録 (c.Info)、データベース インタラクション (c.SQL)、サービス呼び出し (c.GetHTTPService)、トレース (c.Trace) などの機能にどのように直接アクセスできるかに注目してください。 (c).
GoFr コンテキストはすべての HTTP ハンドラーで使用でき、アプリケーションのさまざまな側面を一元的に管理する方法を提供することで、開発エクスペリエンスが大幅に向上します。この統合により、開発者は GoFr の機能を活用して効果的なコンテキスト管理を行いながら、ビジネス ロジックに集中できるようになります。
プログラム設計に関しては、Golang コンテキスト パッケージは非常に便利なツールです。 Go の Context は、リクエスト範囲のデータ、キャンセル信号、期限を管理するための強力なツールとして機能します。マイクロサービス、API、Web アプリケーションのいずれを構築している場合でも、コンテキストによってクリーンなリソース処理と一貫した動作が保証されます。
GoFr をチェックアウトすると、それは Github リポジトリであり、⭐ を付けてサポートします。
以上がGo と GoFr のコンテキストの理解と活用の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。