[REFACTOR] XRPL 에스크로 큐 backoff 최적화 및 재연결 안정성 개선#49
Conversation
📝 WalkthroughWalkthrough이 PR은 XRPL 기반 결제 시스템의 안정성을 개선하기 위해 세 가지 변화를 포함합니다: MongoDB 복제 세트 자동 초기화, 결제 재시도 백오프 타이밍 단축(60초→5초), XRPL WebSocket 재연결 로직 강화로 빠른 장애 복구를 실현합니다. ChangesXRPL 통합 안정성 개선
Sequence DiagramsequenceDiagram
participant Caller as 호출자
participant XrplService
participant Client as XRPL Client
Caller->>XrplService: connect() 호출
alt 이미 연결됨
XrplService-->>Caller: 즉시 반환
else 연결 필요
alt connectPromise 존재 (연결 중)
XrplService->>XrplService: 기존 Promise 대기
else 재연결 필요
XrplService->>XrplService: 기존 Client 폐기
XrplService->>Client: 새 Client 생성 (3초 timeout)
Client-->>XrplService: Client 생성 완료
end
XrplService->>Client: connect() 시도
alt 성공
Client-->>XrplService: 연결 완료
XrplService-->>Caller: Promise 해제 후 반환
else 실패
Client-->>XrplService: 에러 (URL 포함 로그)
XrplService-->>Caller: 예외 재던짐
end
end
핵심 검토 포인트
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/modules/xrpl/xrpl.service.ts (1)
99-101: ⚡ Quick win재연결 전 기존 Client 정리 권장
새로운
Client를 생성하기 전에 기존this.client가 존재하는 경우 명시적으로 정리하는 것이 좋습니다. 현재 코드는 연결되지 않은 상태의 기존 Client를 덮어쓰기만 하므로, 이벤트 리스너나 타이머 등의 리소스가 남아있을 수 있습니다.반복적인 재연결 시나리오에서 점진적 리소스 누수 가능성이 있습니다.
♻️ 권장 수정
if (!this.connectPromise) { // 연결이 끊긴 상태에서 재연결 시 기존 Client를 버리고 새로 생성 // 기존 Client를 재사용하면 "Websocket connection never cleaned up" 에러 발생 + if (this.client) { + await this.client.disconnect().catch(() => {}); + } this.client = new Client(this.wsUrl, { connectionTimeout: 3_000 });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/modules/xrpl/xrpl.service.ts` around lines 99 - 101, Before creating a new Client(this.wsUrl...), ensure any existing this.client is cleaned up: if this.client exists, call its graceful shutdown method (e.g., await this.client.disconnect() or this.client.close() if available), remove any event listeners (e.g., this.client.removeAllListeners()), clear related timers, and set this.client = undefined before assigning the new Client; wrap shutdown in try/catch to avoid swallowing errors and reference the this.client and Client(...) symbols so the cleanup occurs immediately prior to new Client(...) creation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docker-compose.yml`:
- Around line 18-26: The mongo-init service's rs.initiate call sets the replica
member host to "localhost:27017" which will mismatch client connections; update
the rs.initiate invocation (the entrypoint block that calls rs.initiate) to use
the Docker service hostname "mongo:27017" as the member host so the replica set
member address matches how the app connects (i.e., change the host value inside
rs.initiate from "localhost:27017" to "mongo:27017").
---
Nitpick comments:
In `@src/modules/xrpl/xrpl.service.ts`:
- Around line 99-101: Before creating a new Client(this.wsUrl...), ensure any
existing this.client is cleaned up: if this.client exists, call its graceful
shutdown method (e.g., await this.client.disconnect() or this.client.close() if
available), remove any event listeners (e.g., this.client.removeAllListeners()),
clear related timers, and set this.client = undefined before assigning the new
Client; wrap shutdown in try/catch to avoid swallowing errors and reference the
this.client and Client(...) symbols so the cleanup occurs immediately prior to
new Client(...) creation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: b2956ee4-889d-430b-9777-8891c55a27c5
📒 Files selected for processing (3)
docker-compose.ymlsrc/modules/outbox/outbox-watcher.service.tssrc/modules/xrpl/xrpl.service.ts
Resolves #31
문제
기존
backoff: { type: "exponential", delay: 60_000 }설정으로XRPL 네트워크 일시 장애 시 재시도 최대 누적 대기가 ~17시간에 달했습니다.
XRPL 트랜잭션 완료 시간이 3 ~ 5초임을 감안하면 과도한 설정이었습니다.
또한 연결이 끊긴 후 재연결 시 xrpl.js Client를 재사용해
"Websocket connection never cleaned up"에러가 발생하는 버그가 있었습니다.변경 사항
1. Backoff delay 단축 (
outbox-watcher.service.ts)delay: 60_000→delay: 5_0002. XRPL connectionTimeout 단축 (
xrpl.service.ts)connectionTimeout: 3_0003. 재연결 시 Client 새로 생성 (
xrpl.service.ts)"Websocket connection never cleaned up"에러 제거4. 개발 도구 (
scripts/bull-board.ts)npx ts-node scripts/bull-board.ts→ http://localhost:3001/queues5. MongoDB Replica Set (
docker-compose.yml)Chaos Test 결과
toxiproxy로 XRPL WebSocket 연결을 강제 차단/복구하며 실측
delay=2000, connectionTimeout=5s (테스트 1)
delay=5000, connectionTimeout=3s (테스트 2 — never cleaned up 버그 있음)
delay=5000, connectionTimeout=3s (최종 — connect() 수정 후)
결과
delay × (2ⁿ - 1)Summary by CodeRabbit
릴리스 노트
Bug Fixes
Refactor