MyZubsterGateway: 지수 백오프 (Exponential Backoff)를 이용한 신뢰할 수 있는 웹훅 (Webhook) 시스템 구축
요약
MyZubsterGateway에서 웹훅 전송의 신뢰성을 높이기 위해 지수 백오프(Exponential Backoff) 기반의 재시도 메커니즘을 구축한 사례를 다룹니다. 헬스 체크 엔드포인트와 테스트 엔드포인트를 통해 시스템의 관측성과 안정성을 강화하는 방법을 설명합니다.
핵심 포인트
- 지수 백오프를 활용해 다운스트림 서비스의 부하를 방지하며 재시도 수행
- GET /api/health 엔드포인트를 통한 서비스 상태 모니터링 구현
- 실패한 웹훅에 대한 추적성을 확보하여 주문 상태 불일치 문제 해결
- 테스트 엔드포인트를 통해 실제 결제 없이 재시도 로직 검증 가능
헬스 체크 (Health Check)를 추가한 이유, 재시도 메커니즘 (Retry Mechanism), 그리고 MongoDB 퍼즐을 어떻게 해결했는지에 대한 심층 분석입니다.
배경: 이것이 중요한 이유
MyZubster는 Monero 결제와 Tor 익명성을 기반으로 하는 P2P 서비스를 위한 오픈 소스, 프라이버시 우선 생태계입니다. 그 중심에는 MyZubsterGateway가 있으며, 이는 모든 Monero 상호작용을 처리하는 엔진 역할을 합니다. 즉, 각 주문에 대한 고유한 하위 주소 (Subaddress) 생성, 결제 모니터링, 그리고 결제가 확인되었을 때 웹훅 (Webhook) 알림을 전송하는 역할을 수행합니다.
하지만 공백이 있었습니다. 프로덕션 (Production) 환경에서 신뢰성은 선택 사항이 아닙니다. 가맹점의 서버가 일시적으로 다운되었거나 네트워크 오류가 발생하는 등의 이유로 웹훅이 실패하면, 주문 상태가 업데이트되지 않을 수 있습니다. 이는 문제입니다. 오늘 우리는 이 문제를 해결했습니다.
우리가 구축한 것
- 헬스 체크 (Health Check) 엔드포인트 (Endpoint)
게이트웨이의 상태를 모니터링하기 위해 간단하지만 필수적인 GET /api/health 엔드포인트를 추가했습니다. 이는 모든 관측성 (Observability) 전략의 첫 번째 방어선으로, 서비스가 살아있는지 확인하기 위한 빠른 핑 (Ping) 역할을 합니다.
javascript
// In server.js
app.get('/api/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
- 지수 백오프 (Exponential Backoff)를 이용한 웹훅 (Webhook) 재시도 메커니즘 (Retry Mechanism)
이것이 핵심 기능입니다. 우리는 지수 백오프 (Exponential Backoff) 전략을 사용하여 실패한 웹훅 전송을 자동으로 재시도하는 WebhookService를 구축했습니다. 단순히
왜 지수 백오프 (Exponential Backoff)인가요? 만약 웹훅 (Webhook)이 일시적인 문제(예: 서버 재시작)로 인해 실패한다면, 즉시 재시도하는 것은 도움이 되지 않습니다. 점진적으로 대기 시간을 늘림으로써, 다운스트림 서비스 (downstream service)에 요청을 과도하게 보내지 않으면서도 해당 서비스가 복구될 시간을 줄 수 있습니다.
- PaymentMonitor와의 통합
이제 PaymentMonitor는 결제가 확인되었을 때 WebhookService를 사용합니다:
// paymentMonitor.js 내
if (result.status === 'confirmed') {
const webhookResult = await WebhookService.sendWebhookAsync(
tx.webhookUrl,
{
orderId: tx.orderId,
amount: tx.amount,
status: 'confirmed',
txHash: result.txHash
}
);
}
만약 웹훅 (Webhook)이 (모든 재시도 후에) 영구적으로 실패하면, 주문은 그에 따라 표시됩니다. 따라서 우리는 어떤 일이 일어났는지에 대한 추적을 절대 놓치지 않습니다.
- 테스트 엔드포인트 (Test Endpoint)
실제 결제를 기다리지 않고도 재시도 로직 (retry logic)을 검증할 수 있도록 POST /api/test-webhook 테스트 엔드포인트를 추가했습니다:
curl -X POST [http://localhost:3002/api/test-webhook](http://localhost:3002/api/test-webhook) \
-H "Content-Type: application/json" \
-d '{"targetUrl":"[https://your-webhook-endpoint","payload":{"test":true}}](https://your-webhook-endpoint%22,%22payload%22:%7B%22test%22:true%7D%7D)'
이유: 결제 시스템에서의 신뢰성
결제 게이트웨이 (payment gateway)에서 웹훅 (Webhook) 전달은 선택 사항이 아닙니다. 사용자가 서비스에 대해 결제하면, 마켓플레이스는 주문을 처리하고, 판매자에게 알리고, 다음 단계로 진행하기 위해 즉시 이를 알아야 합니다. 만약 웹훅 (Webhook)이 실패하면:
❌ 판매자가 주문 확인을 받지 못할 수 있음
❌ 구매자가 서비스에 접근하지 못할 수 있음
...
재시도 메커니즘 (retry mechanism)을 통해, 이제 게이트웨이는 결국에는 전달을 보장합니다. 가맹점의 서버가 몇 분 동안 다운되어 있더라도, 서버가 다시 온라인 상태가 되면 웹훅 (Webhook)은 반드시 전달될 것입니다.
우리가 극복한 과제: MongoDB
개발 도중, 우리는 전형적인 인프라 문제를 겪었습니다: MongoDB가 시작되지 않았습니다. 로그에는 다음과 같이 표시되었습니다:
Writing to log file failed, aborting application
문제를 진단한 후 해결 방법은 간단했습니다:
mkdir -p /var/log/mongodb /var/lib/mongodb
chown -R mongodb:mongodb /var/log/mongodb /var/lib/mongodb
chmod 755 /var/log/mongodb /var/lib/mongodb
systemctl restart mongod
교훈: 파일 권한 (file permissions)과 디렉토리 소유권 (directory ownership)을 항상 확인하세요. 작은 간과가 시스템 전체를 차단할 수 있습니다.
실제 코드 작동 방식
전체 흐름은 다음과 같습니다:
사용자가 주문을 생성함 → Gateway가 고유한 Monero 하위 주소 (subaddress)를 생성함
사용자가 해당 하위 주소로 Monero를 전송함
...
다음 단계는?
이것은 시작일 뿐입니다. 로드맵의 다음 단계에는 다음이 포함됩니다:
Monero 메인넷 (Mainnet) 지원 (현재 테스트넷 (testnet) 단계)
모바일 앱을 위한 NFC 결제
...
링크 및 리소스
GitHub Repository: DanielIoni-creator/MyZubsterGateway
Live Demo: https://myzubster.com
...
마치며
결제 게이트웨이 (payment gateway)를 구축하는 것은 단순히 돈을 옮기는 것 이상의 의미를 갖습니다. 그것은 신뢰, 신뢰성, 그리고 개인정보 보호 (privacy)에 관한 것입니다. 오늘 진행한 웹훅 (webhook) 재시도 작업은 작은 세부 사항처럼 보일 수 있지만, 운영 환경 (production)에서는 시스템이 정상적으로 작동하느냐 아니면 소리 없이 실패하느냐를 결정짓는 차이입니다.
모든 웹훅은 중요합니다. 모든 주문은 가치가 있습니다. 그리고 이제 MyZubsterGateway는 그 어느 것도 유실되지 않도록 보장합니다.
만약 여러분도 비슷한 것을 구축하고 있다면, 웹훅 신뢰성에 대한 여러분의 접근 방식에 대해 듣고 싶습니다. 아래에 댓글을 남겨주세요!
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기