- 뜻은 맥락이란 뜻인데, go에선 맥락을 유지하기 위한 Object 정도로 이해하면 된다
- 한번 생성한 Context는 수정할수 없고, 수정을 원하면 새로 생성을 해야 한다
기본 기능
내부값 활용
- 로직에서 유지해야 하는 값을 Context에 담아, 다른 곳에서 필요할 경우 Context에서 꺼내 활용할 수 있다
// 기본 Context 생성
ctx := context.Background()
// Context에 값 추가, 여기서 새로운 Context를 생성한다
ctx = context.WithValue(ctx, "CURRENT_USER", currentUser)
// 함수 파라미터로 Context 전달
callApi(ctx)
...
func callApi(ctx context.Context) error {
var currentUser User
if v := ctx.Value("CURRENT_USER"); v != nil {
// 여기선 타입이 맞는지 비교, ok로 확인할 수 있다
u, ok := v.(User)
if !ok {
return errors.New("Not Authroized")
}
currentUser = u
...
}
return errors.New("Not Authroized")
}
Cancel
- 보통 개발할 때 go 루틴으로 여러 작업을 수행할 수 있게 띄워주는데, 이를 남발하면 시스템이 망가질 수 있다, 그래서 go 루틴에선 종료가 되어야 하는 보장이 필요한데 이를 Context의 Cancel로 활용할 수 있다
func longFunc() string {
<-time.After(time.Second * 10)
return "success"
}
func longFuncWithCtx(ctx context.Context) (string, error) {
done := make(chan string)
go func() {
done <- longFunc()
}()
select {
case result := <-done:
return result, nil
// Context의 Done은 Context가 강제 종료되었을 때 받게 되는 채널
case <- ctx.Done():
// Err는 Context가 종료되고 발생한 에러
return "fail", ctx.Err()
}
}
...
// longFuncWithCtx을 호출하는데, Context의 WithCancel 사용
ctx, cancel := context.WithCancel(context.Background())
go func() {
// Go루틴을 종료해야 될 상황이면 cancel을 호출하여 Context에게 취소 신호를 전달
cancel()
}()
result, err := longFuncWithCtx(ctx)
...
// 만약 여러 Go루틴을 한꺼번에 제어하고 싶다면 아래처럼 짜도 된다
ctx, cancel := context.WithCancel(context.Background())
var wg sync.WaitGroup
for i := 0; i < jobCount; i++ {
wg.Add(1)
go func() {
defer wg.Done()
result, err := longFuncWithCtx(ctx)
...
}()
}
Deadline, Timeout
- 특정 시간이 지났을 경우 로직 취소 또는 에러 처리를 위해 타임아웃을 세팅해줄 수 있다
- Deadline, Timeout 2가지가 있는데
- Deadline은 Time을 받으며, 해당 시간이 지나면 취소 신호가 전달
- Timeout은 Duration, 남은 시간을 받으며, 남은 시간 값이 지나가면 취소 신호가 전달
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, d time.Duration) (Context, CancelFunc)
- 보통은 Deadline보단 Timeout을 많이 쓰는 듯 하다
ctx, cancel := context.WithTimeout(context.Background(), time.Second * 3)
go func() {
cancel()
}()
start := time.Now()
result, err := longFuncWithCtx(ctx)
fmt.Printf("duration:%v, result:%s\\n", time.Since(start), result)