nest, node js기반 배치서버 개발
2025. 11. 3. 18:28ㆍNodeJs
반응형
좋아요 👍
아래는 NowSwing과 같은 NestJS/Node.js 환경에서 바로 사용할 수 있는
Node 기반 배치 서버 구조 + 실행 예시 코드입니다.
이 구조는 다음을 전제로 설계되어 있습니다 👇
- 예약/결제 시스템 백엔드가 NestJS로 되어 있음
- DB는 Prisma(MySQL) 기반
- 예약 만료, 결제 상태 동기화, 알림 발송 같은 Job을 자동 처리
- @nestjs/schedule 또는 BullMQ 기반으로 확장 가능
🗂️ 1️⃣ 폴더 구조 예시
batch/
├─ main.ts
├─ app.module.ts
├─ jobs/
│ ├─ reservation-expire.job.ts # 예약 만료 처리
│ ├─ payment-sync.job.ts # 결제 상태 동기화
│ └─ notify.job.ts # 알림/이메일 발송
├─ services/
│ └─ reservation.service.ts
└─ utils/
└─ logger.ts
⚙️ 2️⃣ package.json 스크립트
{
"name": "nowswing-batch",
"version": "1.0.0",
"scripts": {
"start": "node dist/main.js",
"start:dev": "ts-node src/main.ts",
"build": "tsc"
},
"dependencies": {
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
"@nestjs/schedule": "^3.0.0",
"@nestjs/config": "^3.0.0",
"rxjs": "^7.8.1",
"prisma": "^5.0.0",
"@prisma/client": "^5.0.0"
}
}
🚀 3️⃣ main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.createApplicationContext(AppModule);
console.log('✅ Batch server started');
}
bootstrap();
💡 createApplicationContext() 는 HTTP 서버를 띄우지 않고
DI 컨테이너만 구동해서 배치 로직을 실행할 수 있게 합니다.
🧩 4️⃣ app.module.ts
import { Module } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule';
import { ConfigModule } from '@nestjs/config';
import { ReservationExpireJob } from './jobs/reservation-expire.job';
import { ReservationService } from './services/reservation.service';
import { PrismaClient } from '@prisma/client';
@Module({
imports: [ConfigModule.forRoot(), ScheduleModule.forRoot()],
providers: [ReservationExpireJob, ReservationService, PrismaClient],
})
export class AppModule {}
⏰ 5️⃣ 예약 만료 처리 Job — jobs/reservation-expire.job.ts
import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { ReservationService } from '../services/reservation.service';
@Injectable()
export class ReservationExpireJob {
private readonly logger = new Logger(ReservationExpireJob.name);
constructor(private readonly reservationService: ReservationService) {}
// 매 1분마다 실행
@Cron(CronExpression.EVERY_MINUTE)
async handleExpiredReservations() {
this.logger.log('🔍 Checking expired reservations...');
await this.reservationService.cancelExpiredReservations();
this.logger.log('✅ Reservation expire job done.');
}
}
🗃️ 6️⃣ 예약 처리 서비스 — services/reservation.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
@Injectable()
export class ReservationService {
constructor(private prisma: PrismaClient) {}
async cancelExpiredReservations() {
const now = new Date();
const expired = await this.prisma.reservation_v2.findMany({
where: {
status: 'HOLD',
expiredAt: { lt: now },
deletedAt: null,
},
});
for (const r of expired) {
await this.prisma.reservation_v2.update({
where: { id: r.id },
data: { status: 'CANCELLED', updatedAt: now },
});
console.log(`⛳ Reservation ${r.id} canceled`);
}
}
}
🧰 7️⃣ 실행 방법
# 1. 빌드
npm run build
# 2. 실행 (HTTP 서버 없음)
node dist/main.js
또는 개발 중에는:
npm run start:dev
⚙️ 8️⃣ 확장 방안 (대용량 환경)
기능 방법
| 동시성 처리 향상 | Promise.all() / BullMQ Queue 적용 |
| 다중 코어 활용 | PM2 Cluster (pm2 start dist/main.js -i max) |
| AWS 서버리스로 전환 | Lambda + EventBridge 스케줄링 |
| 결제 동기화/정산 추가 | 별도 job 파일 추가 (payment-sync.job.ts) |
✅ 결론
이 구조는 다음과 같은 특징을 가집니다 👇
- NestJS 환경 그대로 → 기존 서비스 로직 재사용
- @nestjs/schedule 기반 → 외부 툴 없이 크론 스케줄링 가능
- Prisma/MySQL과 자연스럽게 연동
- Node.js의 비동기 I/O로 수천 건 예약 만료도 효율적으로 처리
원하신다면 지금 구조에
👉 결제 상태 동기화(Stripe), 예약 리마인드 알림(SMS/Email) 까지 포함한
멀티 잡(batch) 통합 구조로 확장된 버전도 만들어드릴까요?
반응형
'NodeJs' 카테고리의 다른 글
| node js model 샘플코드 (1) | 2025.02.05 |
|---|---|
| Node Js로 자바에서 생성한 JWT 검증처리하기 (0) | 2023.05.22 |
| [NODE] express 프로젝트 생성 (1) | 2022.08.02 |
| [NODE] 파일업로드 처리하기 (0) | 2022.02.09 |
| [NODE] 세션 삭제, 로그아웃 처리하기 (0) | 2022.01.26 |