ERP-node/PHASE3.15_BATCH_SERVICES_MI...

507 lines
13 KiB
Markdown
Raw Normal View History

# 📋 Phase 3.15: Batch Services Raw Query 전환 계획
## 📋 개요
배치 관련 서비스들은 총 **24개의 Prisma 호출**이 있으며, 배치 작업 실행 및 관리를 담당합니다.
### 📊 기본 정보
| 항목 | 내용 |
| --------------- | ---------------------------------------------------------- |
| 대상 서비스 | 4개 (BatchExternalDb, ExecutionLog, Management, Scheduler) |
| 파일 위치 | `backend-node/src/services/batch*.ts` |
| 총 파일 크기 | 2,161 라인 |
| Prisma 호출 | 0개 (전환 완료) |
| **현재 진행률** | **24/24 (100%)****전환 완료** |
| 복잡도 | 높음 (외부 DB 연동, 스케줄링, 트랜잭션) |
| 우선순위 | 🔴 높음 (Phase 3.15) |
| **상태** | ✅ **완료** |
---
## ✅ 전환 완료 내역
### 전환된 Prisma 호출 (24개)
#### 1. BatchExternalDbService (8개)
- `getAvailableConnections()` - findMany → query
- `getTables()` - $queryRaw → query (information_schema)
- `getTableColumns()` - $queryRaw → query (information_schema)
- `getExternalTables()` - findUnique → queryOne (x5)
#### 2. BatchExecutionLogService (7개)
- `getExecutionLogs()` - findMany + count → query (JOIN + 동적 WHERE)
- `createExecutionLog()` - create → queryOne (INSERT RETURNING)
- `updateExecutionLog()` - update → queryOne (동적 UPDATE)
- `deleteExecutionLog()` - delete → query
- `getLatestExecutionLog()` - findFirst → queryOne
- `getExecutionStats()` - findMany → query (동적 WHERE)
#### 3. BatchManagementService (5개)
- `getAvailableConnections()` - findMany → query
- `getTables()` - $queryRaw → query (information_schema)
- `getTableColumns()` - $queryRaw → query (information_schema)
- `getExternalTables()` - findUnique → queryOne (x2)
#### 4. BatchSchedulerService (4개)
- `loadActiveBatchConfigs()` - findMany → query (JOIN with json_agg)
- `updateBatchSchedule()` - findUnique → query (JOIN with json_agg)
- `getDataFromSource()` - $queryRawUnsafe → query
- `insertDataToTarget()` - $executeRawUnsafe → query
### 주요 기술적 해결 사항
1. **외부 DB 연결 조회 반복**
- 5개의 `findUnique` 호출을 `queryOne`으로 일괄 전환
- 암호화/복호화 로직 유지
2. **배치 설정 + 매핑 JOIN**
- Prisma `include``json_agg` + `json_build_object`
- `FILTER (WHERE bm.id IS NOT NULL)` 로 NULL 방지
- 계층적 JSON 데이터 생성
3. **동적 WHERE 절 생성**
- 조건부 필터링 (batch_config_id, execution_status, 날짜 범위)
- 파라미터 인덱스 동적 관리
4. **동적 UPDATE 쿼리**
- undefined 필드 제외
- 8개 필드의 조건부 업데이트
5. **통계 쿼리 전환**
- 클라이언트 사이드 집계 유지
- 원본 데이터만 쿼리로 조회
### 컴파일 상태
✅ TypeScript 컴파일 성공
✅ Linter 오류 없음
---
## 🔍 서비스별 상세 분석
### 1. BatchExternalDbService (8개 호출, 943 라인)
**주요 기능**:
- 외부 DB에서 배치 데이터 조회
- 외부 DB로 배치 데이터 저장
- 외부 DB 연결 관리
- 데이터 변환 및 매핑
**예상 Prisma 호출**:
- `getExternalDbConnection()` - 외부 DB 연결 정보 조회
- `fetchDataFromExternalDb()` - 외부 DB 데이터 조회
- `saveDataToExternalDb()` - 외부 DB 데이터 저장
- `validateExternalDbConnection()` - 연결 검증
- `getExternalDbTables()` - 테이블 목록 조회
- `getExternalDbColumns()` - 컬럼 정보 조회
- `executeBatchQuery()` - 배치 쿼리 실행
- `getBatchExecutionStatus()` - 실행 상태 조회
**기술적 고려사항**:
- 다양한 DB 타입 지원 (PostgreSQL, MySQL, Oracle, MSSQL)
- 연결 풀 관리
- 트랜잭션 처리
- 에러 핸들링 및 재시도
---
### 2. BatchExecutionLogService (7개 호출, 299 라인)
**주요 기능**:
- 배치 실행 로그 생성
- 배치 실행 이력 조회
- 배치 실행 통계
- 로그 정리
**예상 Prisma 호출**:
- `createExecutionLog()` - 실행 로그 생성
- `updateExecutionLog()` - 실행 로그 업데이트
- `getExecutionLogs()` - 실행 로그 목록 조회
- `getExecutionLogById()` - 실행 로그 단건 조회
- `getExecutionStats()` - 실행 통계 조회
- `cleanupOldLogs()` - 오래된 로그 삭제
- `getFailedExecutions()` - 실패한 실행 조회
**기술적 고려사항**:
- 대용량 로그 처리
- 통계 쿼리 최적화
- 로그 보관 정책
- 페이징 및 필터링
---
### 3. BatchManagementService (5개 호출, 373 라인)
**주요 기능**:
- 배치 작업 설정 관리
- 배치 작업 실행
- 배치 작업 중지
- 배치 작업 모니터링
**예상 Prisma 호출**:
- `getBatchJobs()` - 배치 작업 목록 조회
- `getBatchJob()` - 배치 작업 단건 조회
- `createBatchJob()` - 배치 작업 생성
- `updateBatchJob()` - 배치 작업 수정
- `deleteBatchJob()` - 배치 작업 삭제
**기술적 고려사항**:
- JSON 설정 필드 (job_config)
- 작업 상태 관리
- 동시 실행 제어
- 의존성 관리
---
### 4. BatchSchedulerService (4개 호출, 546 라인)
**주요 기능**:
- 배치 스케줄 설정
- Cron 표현식 관리
- 스케줄 실행
- 다음 실행 시간 계산
**예상 Prisma 호출**:
- `getScheduledBatches()` - 스케줄된 배치 조회
- `createSchedule()` - 스케줄 생성
- `updateSchedule()` - 스케줄 수정
- `deleteSchedule()` - 스케줄 삭제
**기술적 고려사항**:
- Cron 표현식 파싱
- 시간대 처리
- 실행 이력 추적
- 스케줄 충돌 방지
---
## 💡 통합 전환 전략
### Phase 1: 핵심 서비스 전환 (12개)
**BatchManagementService (5개) + BatchExecutionLogService (7개)**
- 배치 관리 및 로깅 기능 우선
- 상대적으로 단순한 CRUD
### Phase 2: 스케줄러 전환 (4개)
**BatchSchedulerService (4개)**
- 스케줄 관리
- Cron 표현식 처리
### Phase 3: 외부 DB 연동 전환 (8개)
**BatchExternalDbService (8개)**
- 가장 복잡한 서비스
- 외부 DB 연결 및 쿼리
---
## 💻 전환 예시
### 예시 1: 배치 실행 로그 생성
**변경 전**:
```typescript
const log = await prisma.batch_execution_logs.create({
data: {
batch_id: batchId,
status: "running",
started_at: new Date(),
execution_params: params,
company_code: companyCode,
},
});
```
**변경 후**:
```typescript
const log = await queryOne<any>(
`INSERT INTO batch_execution_logs
(batch_id, status, started_at, execution_params, company_code)
VALUES ($1, $2, NOW(), $3, $4)
RETURNING *`,
[batchId, "running", JSON.stringify(params), companyCode]
);
```
### 예시 2: 배치 통계 조회
**변경 전**:
```typescript
const stats = await prisma.batch_execution_logs.groupBy({
by: ["status"],
where: {
batch_id: batchId,
started_at: { gte: startDate, lte: endDate },
},
_count: { id: true },
});
```
**변경 후**:
```typescript
const stats = await query<{ status: string; count: string }>(
`SELECT status, COUNT(*) as count
FROM batch_execution_logs
WHERE batch_id = $1
AND started_at >= $2
AND started_at <= $3
GROUP BY status`,
[batchId, startDate, endDate]
);
```
### 예시 3: 외부 DB 연결 및 쿼리
**변경 전**:
```typescript
// 연결 정보 조회
const connection = await prisma.external_db_connections.findUnique({
where: { id: connectionId },
});
// 외부 DB 쿼리 실행 (Prisma 사용 불가, 이미 Raw Query일 가능성)
const externalData = await externalDbClient.query(sql);
```
**변경 후**:
```typescript
// 연결 정보 조회
const connection = await queryOne<any>(
`SELECT * FROM external_db_connections WHERE id = $1`,
[connectionId]
);
// 외부 DB 쿼리 실행 (기존 로직 유지)
const externalData = await externalDbClient.query(sql);
```
### 예시 4: 스케줄 관리
**변경 전**:
```typescript
const schedule = await prisma.batch_schedules.create({
data: {
batch_id: batchId,
cron_expression: cronExp,
is_active: true,
next_run_at: calculateNextRun(cronExp),
},
});
```
**변경 후**:
```typescript
const nextRun = calculateNextRun(cronExp);
const schedule = await queryOne<any>(
`INSERT INTO batch_schedules
(batch_id, cron_expression, is_active, next_run_at, created_at, updated_at)
VALUES ($1, $2, $3, $4, NOW(), NOW())
RETURNING *`,
[batchId, cronExp, true, nextRun]
);
```
---
## 🔧 기술적 고려사항
### 1. 외부 DB 연결 관리
```typescript
import { DatabaseConnectorFactory } from "../database/connectorFactory";
// 외부 DB 연결 생성
const connector = DatabaseConnectorFactory.create(connection);
const externalClient = await connector.connect();
try {
// 쿼리 실행
const result = await externalClient.query(sql, params);
} finally {
await connector.disconnect();
}
```
### 2. 트랜잭션 처리
```typescript
await transaction(async (client) => {
// 배치 상태 업데이트
await client.query(`UPDATE batch_jobs SET status = $1 WHERE id = $2`, [
"running",
batchId,
]);
// 실행 로그 생성
await client.query(
`INSERT INTO batch_execution_logs (batch_id, status, started_at)
VALUES ($1, $2, NOW())`,
[batchId, "running"]
);
});
```
### 3. Cron 표현식 처리
```typescript
import cron from "node-cron";
// Cron 표현식 검증
const isValid = cron.validate(cronExpression);
// 다음 실행 시간 계산
function calculateNextRun(cronExp: string): Date {
// Cron 파서를 사용하여 다음 실행 시간 계산
// ...
}
```
### 4. 대용량 데이터 처리
```typescript
// 스트리밍 방식으로 대용량 데이터 처리
const stream = await query<any>(
`SELECT * FROM large_table WHERE batch_id = $1`,
[batchId]
);
for await (const row of stream) {
// 행 단위 처리
}
```
---
## 📝 전환 체크리스트
### BatchExternalDbService (8개)
- [ ] `getExternalDbConnection()` - 연결 정보 조회
- [ ] `fetchDataFromExternalDb()` - 외부 DB 데이터 조회
- [ ] `saveDataToExternalDb()` - 외부 DB 데이터 저장
- [ ] `validateExternalDbConnection()` - 연결 검증
- [ ] `getExternalDbTables()` - 테이블 목록 조회
- [ ] `getExternalDbColumns()` - 컬럼 정보 조회
- [ ] `executeBatchQuery()` - 배치 쿼리 실행
- [ ] `getBatchExecutionStatus()` - 실행 상태 조회
### BatchExecutionLogService (7개)
- [ ] `createExecutionLog()` - 실행 로그 생성
- [ ] `updateExecutionLog()` - 실행 로그 업데이트
- [ ] `getExecutionLogs()` - 실행 로그 목록 조회
- [ ] `getExecutionLogById()` - 실행 로그 단건 조회
- [ ] `getExecutionStats()` - 실행 통계 조회
- [ ] `cleanupOldLogs()` - 오래된 로그 삭제
- [ ] `getFailedExecutions()` - 실패한 실행 조회
### BatchManagementService (5개)
- [ ] `getBatchJobs()` - 배치 작업 목록 조회
- [ ] `getBatchJob()` - 배치 작업 단건 조회
- [ ] `createBatchJob()` - 배치 작업 생성
- [ ] `updateBatchJob()` - 배치 작업 수정
- [ ] `deleteBatchJob()` - 배치 작업 삭제
### BatchSchedulerService (4개)
- [ ] `getScheduledBatches()` - 스케줄된 배치 조회
- [ ] `createSchedule()` - 스케줄 생성
- [ ] `updateSchedule()` - 스케줄 수정
- [ ] `deleteSchedule()` - 스케줄 삭제
### 공통 작업
- [ ] import 문 수정 (모든 서비스)
- [ ] Prisma import 완전 제거 (모든 서비스)
- [ ] 트랜잭션 로직 확인
- [ ] 에러 핸들링 검증
---
## 🧪 테스트 계획
### 단위 테스트 (24개)
- 각 Prisma 호출별 1개씩
### 통합 테스트 (8개)
- BatchExternalDbService: 외부 DB 연동 테스트 (2개)
- BatchExecutionLogService: 로그 생성 및 조회 테스트 (2개)
- BatchManagementService: 배치 작업 실행 테스트 (2개)
- BatchSchedulerService: 스케줄 실행 테스트 (2개)
### 성능 테스트
- 대용량 데이터 처리 성능
- 동시 배치 실행 성능
- 외부 DB 연결 풀 성능
---
## 🎯 예상 난이도 및 소요 시간
- **난이도**: ⭐⭐⭐⭐⭐ (매우 높음)
- 외부 DB 연동
- 트랜잭션 처리
- 스케줄링 로직
- 대용량 데이터 처리
- **예상 소요 시간**: 4~5시간
- Phase 1 (BatchManagement + ExecutionLog): 1.5시간
- Phase 2 (Scheduler): 1시간
- Phase 3 (ExternalDb): 2시간
- 테스트 및 문서화: 0.5시간
---
## ⚠️ 주의사항
### 중요 체크포인트
1. ✅ 외부 DB 연결은 반드시 try-finally에서 해제
2. ✅ 배치 실행 중 에러 시 롤백 처리
3. ✅ Cron 표현식 검증 필수
4. ✅ 대용량 데이터는 스트리밍 방식 사용
5. ✅ 동시 실행 제한 확인
### 성능 최적화
- 연결 풀 활용
- 배치 쿼리 최적화
- 인덱스 확인
- 불필요한 로그 제거
---
**상태**: ⏳ **대기 중**
**특이사항**: 외부 DB 연동, 스케줄링, 트랜잭션 처리 포함
**⚠️ 주의**: 배치 시스템의 핵심 기능이므로 신중한 테스트 필수!