Goのcontextを復習した

publish: 2023-05-23

Context とは

Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.

出典:https://pkg.go.dev/context#pkg-overview

簡単に訳すと、こんな感じ

処理の締め切り・キャンセル信号・API 境界やプロセス間を横断する必要のある

リクエストスコープな値を伝達させることができます。

context の定義は以下の通りです

type Context interface {
// Deadline 期限を返す
Deadline() (deadline time.Time, ok bool)
// Done チャネルを返す。チャネルはキャンセル・期限切れの場合は閉じる
Done() <-chan struct{}
// Err Doneが閉じた理由を返す
Err() error
// Value Contextに格納した値を返す
Value(key interface{}) interface{}
}

出典: https://pkg.go.dev/context#Context

context.Backgroud() context の初期化

0 の状態からコンテキストを生成するにはcontext.Backgroud()を用いる

これは、「キャンセルされない」「deadline を持たない」「共有する値を持たない」状態

context.Withcancel() キャンセルを行う

上記で初期化した値にcontext.WithCancel()を渡すことで、

Doneからキャンセル有無が判断できる context」と「戻り値のコンテキストをキャンセルするための関数」を取得できます

func WithCancel(parent Context) (ctx Context, cancel CancelFunc)

例えば、以下のような形で渡すことで動作する

ctx, cancel := context.WithCancel(context.Backgroud())
// cancel() ctx.Done()で得られるチャネルがcloseされる
cancel()

context.WithDeadine() 自動タイムアウトの行う

func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)

context.WithDeadline()は、引数で渡された親 context の設定を引き継いだ上で

Done メソッドチャネルが第二引数で指定した時刻に自動で close される新たな context になる

タイムアウト前にキャンセルを行うたい場合は、cancel()を呼び出すことでも close できる

// ctxはtime.Now().Add(time.Second)に自動キャンセルされる
ctx, cancel := context.WithDeadline(context.Backgroud(), time.Now().Add(time.Second))
// 明示的にcancelさせることもできる
cancel()

context.WithDeadline()を使うことで時刻タイムアウトをできましたが、

context.WithTimeout()を使うことで時間でタイムアウトさせることも可能です

タイムアウトの有無判定

// ~~ 略~~
case result, ok := <-gen:
if ok {
fmt.Println(result)
} else{
fmt.Println(result)
break
}

これにより、gen チャネルの close 処理が行われるようになる

そのため、タイムアウトかどうかを判定するにはgenチャネルからの受信が、 チャネルcloseによるものか否かを見るだけで判定できる

Deadline メソッドによる、時刻確認、タイムアウトの有無

type Context interface {
Deadline() (deadline time.Time, ok bool)
}

第二引数の bool を確認することで、その context がタイムアウトに設定されるか判定できる

設定されている場合は、第一引数にタイムアウト時刻が格納される

Err  キャンセルなのかタイムアウトなのか判定する

type Context interface {
Err() error
}

context の Err メソッドは、context がキャンセルされた時は nil

明示的にキャンセルされた場合は、Canceled エラー

タイムアウトしていた場合は、DeadlineExceeded エラー

Value 値の付加

func WithValue(parent Context, key, val interface{}) Context

WithValue を使うことで、context に値を加えることができます。

引数 key は key が、val には value を内部に持ちます。

// ctx内部にkeyが"userID", valueが2入る
ctx = context.WithValue(parentCtx, "userID", 2)