재시도 전략
네트워크 일시 장애, Rate Limit 초과 등으로 API 호출이 실패할 수 있습니다.
적절한 재시도 전략을 구현하면 발송 성공률을 높이고 서버 부하를 줄일 수 있습니다.
재시도 대상 vs 비대상
모든 오류에 재시도를 해서는 안 됩니다. 오류 유형에 따라 구분해야 합니다.
| HTTP 상태 | 원인 | 재시도 여부 |
|---|---|---|
200 | 성공 | — |
400 | 요청 형식 오류 | ✗ 재시도 불필요 (코드 수정 필요) |
401 | 인증 실패 (만료된 토큰 등) | ✓ 토큰 갱신 후 재시도 |
429 | Rate Limit 초과 | ✓ 대기 후 재시도 |
500 | 서버 내부 오류 | ✓ 재시도 |
502 / 503 | 일시적 서버 불가 | ✓ 재시도 |
지수 백오프 (Exponential Backoff)
429 또는 5xx 오류 발생 시 즉시 재시도하면 서버 부하가 가중됩니다.
대기 시간을 지수적으로 늘리는 방식을 권장합니다.
1차 실패 → 1초 대기 → 재시도
2차 실패 → 2초 대기 → 재시도
3차 실패 → 4초 대기 → 재시도
4차 실패 → 8초 대기 → 재시도
5차 실패 → 실패 큐로 이동
구현 예시 (JavaScript)
async function sendWithRetry(payload, maxRetries = 5) {
let delay = 1000; // 1초
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const res = await fetch('https://mars.ibapi.kr/api/comm/v1/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': process.env.BIZGO_API_KEY,
},
body: JSON.stringify(payload),
});
if (res.ok) return await res.json();
const status = res.status;
// 재시도 불필요한 오류
if (status === 400 || status === 403) throw new Error(`Non-retryable error: ${status}`);
// 재시도 가능한 오류
if (status === 429 || status >= 500) {
console.warn(`Attempt ${attempt + 1} failed (${status}), retrying in ${delay}ms...`);
await new Promise(r => setTimeout(r, delay));
delay *= 2; // 지수 증가
continue;
}
} catch (err) {
if (attempt === maxRetries - 1) throw err;
await new Promise(r => setTimeout(r, delay));
delay *= 2;
}
}
throw new Error('Max retries exceeded');
}
실패 큐(Dead Letter Queue) 패턴
최대 재시도 후에도 실패한 요청은 버리지 말고 별도 큐에 저장해 추후 수동 처리하거나 알림을 발송합니다.
발송 요청
│
▼
API 호출 실패
│
├─ 재시도 가능? ──→ 재시도 큐 → 지수 백오프 재시도
│
└─ 재시도 한도 초과? ──→ 실패 큐 → 알림 발송 + 수동 검토
Rate Limit 대응
비즈고의 발송 Rate Limit은 200 TPS입니다. 초과 시 HTTP 429 응답이 반환됩니다.
대량 발송 시 권장 처리 방식:
- 배치 분할: 1,000건 이상 발송 시 배치로 나눠 발송
- 발송 간격 조절: TPS를 넘지 않도록 발송 속도 제어
- 429 감지 즉시 대기:
Retry-After헤더 또는 고정 대기 후 재시도
→ 자세한 내용: Rate Limit 정책