Concurrency
context: WithCancelCauseではErrとCauseが異なる
キャンセル状態はcontext.Canceledのままで、業務上の失敗原因はcontext.Causeから取り出します。
Sourcecancel_cause.go
Go 1.22
package contextflow
import (
"context"
"errors"
)
var ErrUpstreamUnavailable = errors.New("upstream unavailable")
func WaitForCancelCause(ctx context.Context) (state error, cause error) {
<-ctx.Done()
return ctx.Err(), context.Cause(ctx)
}
func CanceledWithCause() (state error, cause error) {
ctx, cancel := context.WithCancelCause(context.Background())
cancel(ErrUpstreamUnavailable)
return WaitForCancelCause(ctx)
}Testcancel_cause_test.go
Go 1.22
package contextflow
import (
"context"
"errors"
"testing"
)
func TestWithCancelCauseではErrはCanceledでCauseは指定した原因になる(t *testing.T) {
state, cause := CanceledWithCause()
if !errors.Is(state, context.Canceled) {
t.Fatalf("state = %v, want %v", state, context.Canceled)
}
if !errors.Is(cause, ErrUpstreamUnavailable) {
t.Fatalf("cause = %v, want %v", cause, ErrUpstreamUnavailable)
}
}01Assertion
このテストで確認できること
- WithCancelCauseにErrUpstreamUnavailableを渡してキャンセルする
- Errはcontext.Canceled、Causeは指定した業務エラーとして観測する
呼び出し停止の状態と、停止に至った原因を区別したいときにWithCancelCauseを使います。下流ではctx.Err()で終了状態を、context.Cause(ctx)でログ・応答・再試行判断に必要な原因を読み分けます。
OBSERVED RESULT
ctx.Err() → context canceled
context.Cause() → upstream unavailable