PHpullh
학습 라이브러리/Go/컨텍스트(context) 패키지 활용

GO · 고루틴/채널

컨텍스트(context) 패키지 활용

context 패키지는 고루틴 간 취소 신호, 타임아웃, 값 전달을 위한 표준 메커니즘입니다. API 서버에서 요청 취소, 데이터베이스 쿼리 타임아웃 등 실무에서 필수적으로 사용됩니다.

고루틴/채널중급contextcancellationtimeoutgoroutine

핵심 설명

context 패키지는 고루틴 간 취소 신호, 타임아웃, 값 전달을 위한 표준 메커니즘입니다. API 서버에서 요청 취소, 데이터베이스 쿼리 타임아웃 등 실무에서 필수적으로 사용됩니다.

Go code

package main

import (
	"context"
	"fmt"
	"math/rand"
	"time"
)

// 1. 타임아웃 컨텍스트
func fetchData(ctx context.Context, id int) (string, error) {
	// 실제 작업을 시뮬레이션하는 채널
	ch := make(chan string, 1)
	go func() {
		time.Sleep(time.Duration(rand.Intn(300)) * time.Millisecond)
		ch <- fmt.Sprintf("데이터-%d", id)
	}()

	select {
	case data := <-ch:
		return data, nil
	case <-ctx.Done():
		return "", ctx.Err() // context.DeadlineExceeded 또는 Canceled
	}
}

// 2. 취소 전파
func processItems(ctx context.Context, items []int) []string {
	results := make([]string, 0, len(items))
	for _, item := range items {
		select {
		case <-ctx.Done():
			fmt.Println("  작업 취소됨:", ctx.Err())
			return results
		default:
			data, err := fetchData(ctx, item)
			if err != nil {
				fmt.Printf("  항목 %d 실패: %v\n", item, err)
				continue
			}
			results = append(results, data)
			fmt.Printf("  항목 %d 완료: %s\n", item, data)
		}
	}
	return results
}

// 3. 값 전달 (요청 ID 등)
type contextKey string

const requestIDKey contextKey = "requestID"

func withRequestID(ctx context.Context, id string) context.Context {
	return context.WithValue(ctx, requestIDKey, id)
}

func getRequestID(ctx context.Context) string {
	if id, ok := ctx.Value(requestIDKey).(string); ok {
		return id
	}
	return "unknown"
}

func main() {
	// 타임아웃 컨텍스트: 200ms 제한
	fmt.Println("=== 타임아웃 테스트 ===")
	ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
	defer cancel()
	results := processItems(ctx, []int{1, 2, 3, 4, 5})
	fmt.Printf("완료된 항목: %d개\n\n", len(results))

	// 수동 취소
	fmt.Println("=== 수동 취소 테스트 ===")
	ctx2, cancel2 := context.WithCancel(context.Background())
	go func() {
		time.Sleep(100 * time.Millisecond)
		cancel2() // 100ms 후 취소
	}()
	processItems(ctx2, []int{10, 20, 30})

	// 값 전달
	fmt.Println("\n=== 요청 ID 전달 ===")
	ctx3 := withRequestID(context.Background(), "req-abc-123")
	fmt.Println("요청 ID:", getRequestID(ctx3))
}

학습 팁

함수의 첫 번째 매개변수로 context.Context를 받는 것이 Go 관례입니다. context.WithValue는 요청 범위 데이터(trace ID 등)에만 사용하고, 함수 매개변수를 대체하지 마세요.

주의할 점

context.WithTimeout이나 context.WithCancel로 생성한 컨텍스트는 반드시 defer cancel()로 리소스를 해제해야 합니다. 안 하면 컨텍스트가 부모의 타이머 만료까지 메모리에 남습니다.

자주 묻는 질문

컨텍스트(context) 패키지 활용란 무엇인가요?

context 패키지는 고루틴 간 취소 신호, 타임아웃, 값 전달을 위한 표준 메커니즘입니다. API 서버에서 요청 취소, 데이터베이스 쿼리 타임아웃 등 실무에서 필수적으로 사용됩니다.

컨텍스트(context) 패키지 활용 학습 시 주의할 점은 무엇인가요?

context.WithTimeout 이나 context.WithCancel 로 생성한 컨텍스트는 반드시 defer cancel() 로 리소스를 해제해야 합니다. 안 하면 컨텍스트가 부모의 타이머 만료까지 메모리에 남습니다.