Go에서 Context를 활용한 HTTP 요청 타임아웃 처리
문제 상황
사내 결제 시스템에서 외부 PG사 API를 호출하는데, 재택근무 이후 간헐적으로 응답이 느려지거나 타임아웃이 발생했다. 기존 코드는 http.Get()을 직접 사용해 타임아웃 제어가 불가능했다.
해결 방법
context.WithTimeout을 사용해 요청별로 타임아웃을 설정했다.
func fetchPaymentStatus(orderID string) (*PaymentStatus, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET",
fmt.Sprintf("https://api.pg.example/orders/%s", orderID), nil)
if err != nil {
return nil, err
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
// 응답 처리...
}
추가 개선
여러 API를 병렬로 호출해야 하는 경우, sync.WaitGroup과 함께 사용했다.
func fetchMultipleStatus(orderIDs []string) ([]*PaymentStatus, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
results := make([]*PaymentStatus, len(orderIDs))
var wg sync.WaitGroup
errCh := make(chan error, len(orderIDs))
for i, id := range orderIDs {
wg.Add(1)
go func(idx int, orderID string) {
defer wg.Done()
status, err := fetchWithContext(ctx, orderID)
if err != nil {
errCh <- err
return
}
results[idx] = status
}(i, id)
}
wg.Wait()
close(errCh)
if len(errCh) > 0 {
return nil, <-errCh
}
return results, nil
}
결과
- 최대 응답 시간이 3초로 제한되어 전체 시스템 안정성 향상
- context 취소로 불필요한 goroutine 누수 방지
- 모니터링 지표 개선: timeout 발생률 추적 가능
재택 환경에서 네트워크 불안정성이 증가했는데, context를 통한 명시적 타임아웃 관리로 문제를 해결했다.