context
パッケージを使用して、実行時間の長いプロセスを管理します。Server
はStore
を受け取り、http.HandlerFunc
を返します。Store
は次のように定義されますstore
の Fetch
メソッドを呼び出してデータを取得し、それを応答に書き込みます。Store
に対応するスタブがあります。Store
がFetch
を完了できない、より現実的なシナリオを作成したいと思います。Store
に作業をキャンセルしてインターフェースを更新するように指示する方法が必要になります。data
を返すには時間がかかり、キャンセルするように指示されたことを知る方法があります。呼び出し方法を確認しているので、名前をSpyStore
に変更します。Store
インターフェースを実装するメソッドとしてCancel
を追加する必要があります。コンテキストパッケージは、既存のコンテキスト値から新しいコンテキスト値を導出する関数を提供します。これらの値はツリーを形成します。コンテキストが取り消されると、それから派生したすべてのコンテキストも取り消されます。
cancel
関数を返すrequest
から新しいcancellingCtx
を派生させることです。次に、time.AfterFunc
を使用して、その関数が5ミリ秒で呼び出されるようにスケジュールします。最後に、request.WithContext
を呼び出して、この新しいコンテキストをリクエストで使用します。Store
をキャンセルしてはいけません。context
にはメソッドDone()
があり、コンテキストが「完了」または「キャンセル」されたときに信号を送信するチャネルを返します。そのシグナルをリッスンし、それを取得した場合はstore.Cancel
を呼び出しますが、Store
がその前にFetch
を実行した場合は無視します。Fetch
を実行し、結果を新しいチャネルdata
に書き込みます。次に、select
を使用して2つの非同期プロセスに効率的に競合し、応答またはCancel
を書き込みます。*testing.T
を渡すことを忘れないでください。Store
をキャンセルすることに関心を持つことは理にかなっていますか?Store
が他の実行速度の遅いプロセスに依存している場合はどうなりますか? Store.Cancel
がキャンセルを依存するすべてに正しくキャンセルすることを確認する必要があります。context
の主なポイントの1つは、キャンセルを提供する一貫した方法であることです。サーバーへの着信要求はコンテキストを作成し、サーバーへの発信呼び出しはコンテキストを受け入れる必要があります。それらの間の関数呼び出しのチェーンは、コンテキストを伝播する必要があり、オプションで、WithCancel
、WithDeadline
、WithTimeout
、またはWithValue
を使用して作成された派生コンテキストに置き換えます。コンテキストがキャンセルされると、そのコンテキストから派生したすべてのコンテキストもキャンセルされます。
Googleでは、Goプログラマーが、最初の引数として、着信要求と発信要求の間の呼び出しパス上のすべての関数にContextパラメーターを渡す必要があります。これにより、多くの異なるチームが開発したGoコードを適切に相互運用できます。タイムアウトとキャンセルを簡単に制御し、セキュリティ認証情報などの重要な値がGoプログラムを適切に通過するようにします。
context
を介して私たちのStore
に渡し、責任を持たせましょう。そうすることで、context
をその依存関係に渡すこともでき、それらも依存を停止する責任があります。Store
に送信されることと、キャンセルされたときにStore
から発生するエラーを処理することです。Store
インターフェースを更新して、新しい責任を示しましょう。SpyStore
を更新しますcontext
で機能する実際の方法のように動作させる必要があります。data
チャネルに書き込みます。ゴルーチンはctx.Done
をリッスンし、そのチャネルでシグナルが送信されると作業を停止します。select
を使用して、そのゴルーチンが作業を完了するか、キャンセルが発生するのを待ちます。context
を受け入れる独自の関数とメソッドを記述する場合も同様のアプローチをとるので、何が起こっているのかを確実に理解してください。httptest.ResponseRecorder
にはこれを理解する方法がないため、これをテストするために私たち自身のスパイをロールする必要があります。SpyResponseWriter
はhttp.ResponseWriter
を実装します。context
を通過し、発生する可能性のあるすべてのキャンセルを下流の関数に依存しています。context
を受け入れ、それを使ってゴルーチン、select
、およびチャネルを使用してそれ自体をキャンセルする関数の作成方法。http.ResponseWriter
の独自のスパイをロールする方法。context.Value
はどうですか?私の(non-existent)会社でctx.Value
を使用すると、解雇されます
context
を介して値を渡すことを提唱しています。context.Values
の問題は、型付けされていないマップであるため、タイプの安全性がなく、値を実際に含まないように処理する必要があることです。あるモジュールから別のモジュールへのマップキーの結合を作成する必要があり、誰かが何かを変更すると、何かが壊れ始めます。context.Value
からそれらをフェッチしようとするのではなく、型付きパラメーターとしてそれらを置きます。これは静的にチェックされ、誰もが見ることができるように文書化されます。context.Value
のコンテンツは、ユーザーではなくメンテナー向けです。文書化された結果または期待される結果の入力が必要になることはありません。
context
を渡す必要があることは匂いであり、キャンセルに関する言語の欠陥を指摘しているということです。ライブラリレベルではなく、言語レベルで何らかの方法でこれを解決した方が良いと彼は言います。それが発生するまで、実行時間の長いプロセスを管理する場合は、context
が必要になります。