본문으로 건너뛰기
Didit, 신원·사기 방지 인프라 구축 위해 750만 달러 투자 유치
Didit
블로그로 돌아가기
블로그 · 2026년 3월 6일

Go 언어에서 Didit API 오류 처리 및 재시도 마스터하기 (KO)

Go 언어에서 Didit API와 견고한 통합을 구축하려면 정교한 오류 처리 및 재시도 전략이 필요합니다. 이 가이드에서는 Didit의 속도 제한 및 특정 오류 코드 이해부터 모범 사례를 탐구합니다.

작성자: Didit업데이트됨
didit-api-error-handling-retries-go.png

Didit의 속도 제한 이해서비스 중단을 방지하기 위해 X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset 헤더를 활용하여 429 응답에 대한 클라이언트 측 스로틀링 및 지수 백오프를 구현합니다.

오류 유형 구분일시적 오류(예: 네트워크 문제, 서비스 사용 불가)와 영구적 오류(예: 잘못된 API 키, 잘못된 요청)를 구분하여 적절한 재시도 로직을 적용하거나 빠르게 실패하도록 합니다.

견고한 재시도 메커니즘 구현지수 백오프, 지터 및 최대 재시도 횟수를 포함한 구조화된 재시도 루프를 사용하여 일시적인 실패를 원활하게 처리하고 세션 생성과 같은 중요 작업의 신뢰성을 향상시킵니다.

Didit의 개발자 우선 접근 방식이 통합을 간소화합니다.Didit은 명확한 API 문서, 특정 속도 제한 헤더 및 모듈식 아키텍처를 제공하여 Go 개발자가 탄력적인 신원 확인 흐름을 쉽고 자신감 있게 구축할 수 있도록 합니다.

타사 API 통합은 현대 애플리케이션 개발의 초석이며, 신원 확인도 예외는 아닙니다. Didit의 신원 플랫폼과 같은 중요한 서비스를 사용할 때 네트워크 변동, 서비스 문제 및 속도 제한에 통합이 탄력적으로 대응하도록 하는 것이 가장 중요합니다. 이 가이드는 Go를 사용하여 Didit API 통합을 위해 특별히 맞춤화된 고급 오류 처리 및 재시도 전략을 심층적으로 다루며, 견고하고 신뢰할 수 있는 시스템을 구축하는 데 도움을 줍니다.

Didit의 API 오류 환경 이해하기

재시도 로직을 구현하기 전에 발생할 수 있는 오류 유형을 이해하는 것이 중요합니다. Didit의 API는 잘 설계된 많은 서비스와 마찬가지로 HTTP 상태 코드를 통해 다양한 상태를 전달합니다. 표준 2xx 코드는 성공을 나타내지만, 주로 4xx(클라이언트 오류) 및 5xx(서버 오류), 특히 429(너무 많은 요청)에 중점을 둡니다.

Didit의 속도 제한 및 귀하에게 미치는 영향

Didit은 API 안정성을 유지하기 위해 속도 제한을 적용합니다. 이는 통합에서 관리해야 할 중요한 측면입니다. 예를 들어, GET 엔드포인트는 일반적으로 애플리케이션당 분당 300개의 요청이라는 전역 제한이 있으며, session-decision(100rpm) 또는 session-v2-create(600rpm)와 같은 특정 엔드포인트에는 자체적인, 잠재적으로 더 엄격한 제한이 있습니다. 속도 제한에 도달하면 Didit은 429 Too Many Requests 상태 코드와 함께 유용한 헤더를 반환합니다.

  • X-RateLimit-Limit: 현재 창에서 허용되는 최대 요청 수입니다.
  • X-RateLimit-Remaining: 현재 창에서 남은 요청 수입니다.
  • X-RateLimit-Reset: 현재 속도 제한 창이 재설정되는 시간(에포크 초)입니다.
  • Retry-After: (종종 포함됨) 다른 요청을 하기 전에 기다려야 하는 시간(초)입니다.

Go 클라이언트는 이러한 헤더를 적극적으로 모니터링해야 합니다. X-RateLimit-Remaining이 특정 임계값(예: X-RateLimit-Limit의 15%) 아래로 떨어지면 요청을 사전에 스로틀링해야 합니다. 이를 무시하면 지속적인 429 오류가 발생하여 애플리케이션이 Didit의 ID 확인 또는 AML 심사와 같은 제품에서 확인 세션을 생성하거나 결과를 검색하는 기능에 영향을 미칠 수 있습니다.

Go 언어에서 지수 백오프를 사용한 견고한 재시도 전략 구현

일시적인 오류(예: 네트워크 시간 초과, 일시적인 서비스 사용 불가 또는 429)의 경우 재시도가 필수적입니다. 그러나 순진한 재시도는 문제를 악화시킬 수 있습니다. 골드 스탠다드는 지터가 있는 지수 백오프입니다.

지터가 있는 지수 백오프

지수 백오프는 재시도 사이의 대기 시간을 기하급수적으로 늘리는 것을 의미합니다. 지터(작은 무작위 지연 추가)는 중단 후 많은 클라이언트가 동시에 재시도하여 서비스를 다시 압도하는 '벼락떼 문제'를 방지합니다. 다음은 개념적인 Go 예시입니다.

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
	"math/rand"
)

func callDiditAPIWithRetry(url string, maxRetries int) ([]byte, error) {
	client := &http.Client{Timeout: 10 * time.Second}
	rand.Seed(time.Now().UnixNano())

	for i := 0; i <= maxRetries; i++ {
		resp, err := client.Get(url)
		if err != nil {
			// Handle network errors (e.g., connection refused, timeout)
			fmt.Printf("Attempt %d: Network error: %v\n", i+1, err)
			if i == maxRetries {
				return nil, fmt.Errorf("failed after %d retries: %w", maxRetries, err)
			}
			sleepTime := time.Duration(1<<i)*time.Second + time.Duration(rand.Intn(1000))*time.Millisecond // Exponential backoff + jitter
			fmt.Printf("Retrying in %v...\n", sleepTime)
			time.Sleep(sleepTime)
			continue
		}
		defer resp.Body.Close()

		switch resp.StatusCode {
		case http.StatusOK:
			fmt.Printf("Attempt %d: Success!\n", i+1)
			return ioutil.ReadAll(resp.Body)
		case http.StatusTooManyRequests:
			// Respect Retry-After header if present
			retryAfter := resp.Header.Get("Retry-After")
			if retryAfter != "" {
				if sleepSeconds, err := time.ParseDuration(retryAfter + "s"); err == nil {
					fmt.Printf("Attempt %d: Rate limited. Retrying after %v.\n", i+1, sleepSeconds)
					time.Sleep(sleepSeconds)
					continue
				}
			}
			// Fallback to exponential backoff if Retry-After is missing or invalid
			fmt.Printf("Attempt %d: Rate limited (429).\n", i+1)
			if i == maxRetries {
				return nil, fmt.Errorf("rate limited after %d retries", maxRetries)
			}
			sleepTime := time.Duration(1<<i)*time.Second + time.Duration(rand.Intn(1000))*time.Millisecond
			fmt.Printf("Retrying in %v...\n", sleepTime)
			time.Sleep(sleepTime)
			continue
		case http.StatusInternalServerError, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout:
			// Server-side errors that might be transient
			fmt.Printf("Attempt %d: Server error %d. Retrying.\n", i+1, resp.StatusCode)
			if i == maxRetries {
				return nil, fmt.Errorf("server error %d after %d retries", resp.StatusCode, maxRetries)
			}
			sleepTime := time.Duration(1<<i)*time.Second + time.Duration(rand.Intn(1000))*time.Millisecond
			fmt.Printf("Retrying in %v...\n", sleepTime)
			time.Sleep(sleepTime)
			continue
		default:
			// Non-retryable errors (4xx client errors, etc.)
			body, _ := ioutil.ReadAll(resp.Body)
			return nil, fmt.Errorf("non-retryable API error: %d %s, response: %s", resp.StatusCode, resp.Status, string(body))
		}
	}
	return nil, fmt.Errorf("unexpected control flow") // Should not be reached
}

func main() {
	// Example usage: Replace with actual Didit API endpoint
	// For a real integration, you'd be POSTing to /v3/session/ or similar
	// and handling the verification_url.
	apiURL := "https://verification.didit.me/health"
	data, err := callDiditAPIWithRetry(apiURL, 5)
	if err != nil {
		fmt.Println("Failed to call API:", err)
	} else {
		fmt.Println("API Response:", string(data))
	}
}

이 스니펫은 네트워크 오류, 429(Retry-After 존중), 일반적인 5xx 오류를 지수 백오프 및 지터로 처리하는 방법을 보여줍니다. 또한 잘못된 입력으로 인해 재시도해도 해결되지 않는 비재시도 가능한 4xx 오류에 대해 빠르게 실패하는 방법을 보여줍니다. 이는 Didit의 모듈식 아키텍처를 사용하여 확인 세션을 생성하는 것과 같은 작업에 중요합니다.

서킷 브레이커 패턴 구현

재시도는 일시적인 문제에 도움이 되지만, 실패하는 서비스를 계속 재시도하면 서비스가 실제로 중단된 경우 과부하가 걸리거나 리소스가 낭비될 수 있습니다. 이때 서킷 브레이커 패턴이 등장합니다. 서킷 브레이커는 오류를 모니터링하고, 특정 임계값에 도달하면 회로를 '개방'하여 일정 기간 동안 추가 요청을 방지합니다. 기간이 지나면 서비스가 복구되었는지 확인하기 위해 몇 가지 테스트 요청을 허용합니다.

Go에서 sony/gobreaker와 같은 라이브러리를 사용하여 이 패턴을 구현할 수 있습니다.

package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"github.com/sony/gobreaker"
)

var cb *gobreaker.CircuitBreaker

func init() {
	st := gobreaker.Settings{
		Name:        "DiditAPICircuitBreaker",
		MaxRequests: 3, // Allow 3 requests in half-open state
		Interval:    5 * time.Second, // Period to collect data for trip decisions
		Timeout:     10 * time.Second, // Open circuit for 10 seconds
		ReadyToTrip: func(counts gobreaker.Counts) bool {
			return counts.ConsecutiveFailures > 5 // Trip after 5 consecutive failures
		},
		OnStateChange: func(name string, from gobreaker.State, to gobreaker.State) {
			fmt.Printf("Circuit Breaker '%s' changed from %s to %s\n", name, from, to)
		},
	}
	cb = gobreaker.NewCircuitBreaker(st)
}

func callDiditAPIWithCircuitBreaker(url string) ([]byte, error) {
	body, err := cb.Execute(func() (interface{}, error) {
		resp, err := http.Get(url)
		if err != nil {
			return nil, err // Network error
		}
		defer resp.Body.Close()

		if resp.StatusCode != http.StatusOK {
			// Only count 5xx and 429 as failures for circuit breaker
			if resp.StatusCode == http.StatusTooManyRequests || resp.StatusCode >= http.StatusInternalServerError {
				return nil, fmt.Errorf("API returned status %d", resp.StatusCode)
			}
			// For other 4xx errors, we might not want to trip the breaker, but still return an error
			bodyBytes, _ := ioutil.ReadAll(resp.Body)
			return nil, fmt.Errorf("non-retryable API error: %d %s, response: %s", resp.StatusCode, resp.Status, string(bodyBytes))
		}

		return ioutil.ReadAll(resp.Body)
	})

	if err != nil {
		if errors.Is(err, gobreaker.ErrOpenState) {
			return nil, fmt.Errorf("circuit breaker is open: %w", err)
		}
		return nil, err
	}

	return body.([]byte), nil
}

func main() {
	// Example usage
	apiURL := "https://verification.didit.me/health"
	for i := 0; i < 10; i++ {
		data, err := callDiditAPIWithCircuitBreaker(apiURL)
		if err != nil {
			fmt.Printf("Call %d failed: %v\n", i+1, err)
		} else {
			fmt.Printf("Call %d successful: %s\n", i+1, string(data))
		}
		time.Sleep(1 * time.Second)
	}
}

서킷 브레이커를 지수 백오프와 결합하면 애플리케이션이 응답성을 유지하고 어려움을 겪는 외부 서비스를 과부하하지 않도록 합니다. 이는 Didit의 ID 확인 또는 수동 및 능동 생체 인식 확인과 관련된 대량의 신원 확인 요청을 처리할 때 특히 중요합니다.

웹훅 실패 및 비동기 결과 처리

Didit의 API는 종종 웹훅을 통해 비동기적으로 결과를 제공합니다. 예를 들어, 사용자가 ID 확인 흐름을 완료하거나 AML 심사 확인이 완료되었을 때입니다. 웹훅 엔드포인트는 견고해야 합니다. 엔드포인트가 웹훅을 처리하지 못할 경우(예: 5xx 상태 코드 반환) Didit은 웹훅 전달을 재시도합니다. 다음 사항이 중요합니다.

  • 즉시 수신 확인: 처리에 시간이 더 걸리더라도 성공적인 수신을 알리기 위해 가능한 한 빨리 2xx 상태 코드를 반환합니다.
  • 비동기적으로 처리: 웹훅 페이로드를 백그라운드 작업자 또는 메시지 큐(예: Kafka, RabbitMQ)로 전달하여 처리합니다. 이렇게 하면 웹훅 엔드포인트가 Didit의 재시도 시간 초과를 방지합니다.
  • 멱등성: 웹훅 처리 로직이 멱등성인지 확인합니다. Didit이 동일한 웹훅을 여러 번 재시도하고 전달하더라도 시스템은 중복 작업이나 데이터 불일치를 방지하기 위해 한 번만 처리해야 합니다.
  • 서명 확인: Didit 콘솔에서 Webhook Secret Key를 사용하여 웹훅 서명을 항상 확인하여 요청이 Didit에서 실제로 시작되었고 변조되지 않았는지 확인합니다.

Didit이 도움이 되는 방법

Didit은 개발자 경험과 신뢰성을 염두에 두고 설계되었으며, Go 통합을 위한 고급 오류 처리 및 재시도 전략을 본질적으로 단순화하는 기능을 제공합니다. 당사의 개발자 우선 접근 방식은 명확하고 포괄적인 API 문서, 즉각적인 샌드박스 및 통합을 간단하게 만드는 깔끔한 API를 의미합니다.

  • 예측 가능한 속도 제한: Didit은 클라이언트 측 스로틀링 및 백오프 로직을 안내하기 위해 전역 및 엔드포인트별 속도 제한과 표준 HTTP 헤더(X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, Retry-After)를 명확하게 정의합니다. 이 투명성은 ID 확인 및 AML 심사와 같은 서비스에 최적화된 재시도 메커니즘을 구축할 수 있도록 합니다.
  • 모듈식 아키텍처: 당사의 모듈식 신원 기본 요소는 설계상 탄력적인 워크플로우를 구축할 수 있음을 의미합니다. 특정 확인(예: 주소 증명)에 일시적인 문제가 발생하더라도 전체 워크플로우는 관련 없는 확인 단계에 영향을 주지 않고 특정 구성 요소를 조정하거나 재시도하도록 구성할 수 있습니다.
  • AI 기반 신뢰성: Didit의 AI 기반 백엔드는 확장성과 탄력성을 위해 구축되어 발생할 서버 측 오류를 최소화합니다. 이를 통해 지속적인 서비스 중단보다는 네트워크 및 클라이언트 측 문제에 오류 처리를 집중할 수 있습니다.
  • 무료 핵심 KYC 및 유연한 가격 책정: Didit의 무료 티어로 핵심 KYC를 시작하여 생산과 유사한 환경에서 선불 비용 없이 오류 처리 및 재시도 전략을 철저히 테스트할 수 있습니다. 성공적인 확인당 지불 모델은 당사의 성공과 귀하의 성공을 더욱 일치시킵니다.

시작할 준비가 되셨습니까?

Didit의 작동 방식을 확인하시겠습니까? 오늘 무료 데모를 받으세요.

Didit의 무료 티어로 무료로 신원 확인을 시작하세요.

신원 및 사기 방지 인프라.

KYC, KYB, 거래 모니터링, 지갑 심사를 위한 단일 API. 5분 만에 통합하세요.

AI에게 이 페이지 요약 요청
Go 언어 Didit API 오류 처리 및 재시도 심층 분석.