diff --git a/docker-compose.yml b/docker-compose.yml index 66c1ba8..7ad6570 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,10 +3,27 @@ services: mongo: image: mongo:6 restart: unless-stopped + command: ["--replSet", "rs0", "--bind_ip_all"] ports: - "27017:27017" volumes: - mongo_data:/data/db + healthcheck: + test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"] + interval: 10s + timeout: 10s + retries: 5 + start_period: 30s + + mongo-init: + image: mongo:6 + depends_on: + mongo: + condition: service_healthy + entrypoint: > + mongosh --host mongo:27017 --eval + 'try { rs.status(); print("already initiated") } catch(e) { rs.initiate({_id:"rs0",members:[{_id:0,host:"localhost:27017"}]}); print("initiated") }' + restart: "no" redis: image: redis:alpine diff --git a/src/modules/outbox/outbox-watcher.service.ts b/src/modules/outbox/outbox-watcher.service.ts index d5c9217..a575626 100644 --- a/src/modules/outbox/outbox-watcher.service.ts +++ b/src/modules/outbox/outbox-watcher.service.ts @@ -130,11 +130,11 @@ export class OutboxWatcherService if (!acquired) return; // 다른 인스턴스가 먼저 처리함 // 금액 오류는 프로세서에서 즉시 중단, 그 외(네트워크 등)는 적극 재시도 - // 10회, 초기 60초 지수 백오프 → 최대 누적 대기 ~17시간 + // 10회, 초기 5초 지수 백오프 → 최대 누적 대기 ~43분 try { await this.escrowCreateQueue.add(doc.payload as EscrowCreateJobData, { attempts: 10, - backoff: { type: "exponential", delay: 60_000 }, + backoff: { type: "exponential", delay: 5_000 }, }); } catch (err: any) { this.logger.error( diff --git a/src/modules/xrpl/xrpl.service.ts b/src/modules/xrpl/xrpl.service.ts index 56eea7f..ef0f5ec 100644 --- a/src/modules/xrpl/xrpl.service.ts +++ b/src/modules/xrpl/xrpl.service.ts @@ -92,20 +92,31 @@ export class XrplService implements OnModuleInit, OnModuleDestroy { // 중복 websocket 중복 연결 방지 및 재연결 로직 private async connect() { - if (!this.client) { - this.client = new Client(this.wsUrl); - } - if (this.client.isConnected()) { + if (this.client?.isConnected()) { return; } if (!this.connectPromise) { - this.connectPromise = this.client.connect().finally(() => { - this.connectPromise = undefined; - }); + // 연결이 끊긴 상태에서 재연결 시 기존 Client를 버리고 새로 생성 + // 기존 Client를 재사용하면 "Websocket connection never cleaned up" 에러 발생 + this.client = new Client(this.wsUrl, { connectionTimeout: 3_000 }); + this.logger.log(`[XRPL] Connecting to ${this.wsUrl}`); + this.connectPromise = this.client + .connect() + .then(() => { + this.logger.log(`[XRPL] Connected to ${this.wsUrl}`); + }) + .catch((err: Error) => { + this.logger.error( + `[XRPL] Connection failed (${this.wsUrl}): ${err.message}`, + ); + throw err; + }) + .finally(() => { + this.connectPromise = undefined; + }); } await this.connectPromise; - this.logger.log(`Connected to XRPL: ${this.wsUrl}`); } // 신규 지갑 생성