ERP-node/PHASE3.15_BATCH_SERVICES_MI...

13 KiB

📋 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 includejson_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: 배치 실행 로그 생성

변경 전:

const log = await prisma.batch_execution_logs.create({
  data: {
    batch_id: batchId,
    status: "running",
    started_at: new Date(),
    execution_params: params,
    company_code: companyCode,
  },
});

변경 후:

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: 배치 통계 조회

변경 전:

const stats = await prisma.batch_execution_logs.groupBy({
  by: ["status"],
  where: {
    batch_id: batchId,
    started_at: { gte: startDate, lte: endDate },
  },
  _count: { id: true },
});

변경 후:

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 연결 및 쿼리

변경 전:

// 연결 정보 조회
const connection = await prisma.external_db_connections.findUnique({
  where: { id: connectionId },
});

// 외부 DB 쿼리 실행 (Prisma 사용 불가, 이미 Raw Query일 가능성)
const externalData = await externalDbClient.query(sql);

변경 후:

// 연결 정보 조회
const connection = await queryOne<any>(
  `SELECT * FROM external_db_connections WHERE id = $1`,
  [connectionId]
);

// 외부 DB 쿼리 실행 (기존 로직 유지)
const externalData = await externalDbClient.query(sql);

예시 4: 스케줄 관리

변경 전:

const schedule = await prisma.batch_schedules.create({
  data: {
    batch_id: batchId,
    cron_expression: cronExp,
    is_active: true,
    next_run_at: calculateNextRun(cronExp),
  },
});

변경 후:

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 연결 관리

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. 트랜잭션 처리

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 표현식 처리

import cron from "node-cron";

// Cron 표현식 검증
const isValid = cron.validate(cronExpression);

// 다음 실행 시간 계산
function calculateNextRun(cronExp: string): Date {
  // Cron 파서를 사용하여 다음 실행 시간 계산
  // ...
}

4. 대용량 데이터 처리

// 스트리밍 방식으로 대용량 데이터 처리
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 연동, 스케줄링, 트랜잭션 처리 포함
⚠️ 주의: 배치 시스템의 핵심 기능이므로 신중한 테스트 필수!