// 배치 관리 서비스 // 작성일: 2024-12-23 import { PrismaClient } from "@prisma/client"; import { BatchJob, BatchJobFilter, BatchExecution, BatchMonitoring, } from "../types/batchManagement"; const prisma = new PrismaClient(); export class BatchService { /** * 배치 작업 목록 조회 */ static async getBatchJobs(filter: BatchJobFilter): Promise { const whereCondition: any = { company_code: filter.company_code || "*", }; if (filter.job_name) { whereCondition.job_name = { contains: filter.job_name, mode: "insensitive", }; } if (filter.job_type) { whereCondition.job_type = filter.job_type; } if (filter.is_active) { whereCondition.is_active = filter.is_active === "Y"; } if (filter.search) { whereCondition.OR = [ { job_name: { contains: filter.search, mode: "insensitive" } }, { description: { contains: filter.search, mode: "insensitive" } }, ]; } const jobs = await prisma.batch_jobs.findMany({ where: whereCondition, orderBy: { created_date: "desc" }, }); return jobs.map((job: any) => ({ ...job, is_active: job.is_active ? "Y" : "N", })) as BatchJob[]; } /** * 배치 작업 상세 조회 */ static async getBatchJobById(id: number): Promise { const job = await prisma.batch_jobs.findUnique({ where: { id }, }); if (!job) return null; return { ...job, is_active: job.is_active ? "Y" : "N", } as BatchJob; } /** * 배치 작업 생성 */ static async createBatchJob(data: BatchJob): Promise { const { id, config_json, ...createData } = data; const job = await prisma.batch_jobs.create({ data: { ...createData, is_active: data.is_active, config_json: config_json || undefined, created_date: new Date(), updated_date: new Date(), }, }); return { ...job, is_active: job.is_active ? "Y" : "N", } as BatchJob; } /** * 배치 작업 수정 */ static async updateBatchJob( id: number, data: Partial ): Promise { const updateData: any = { ...data, updated_date: new Date(), }; if (data.is_active !== undefined) { updateData.is_active = data.is_active; } const job = await prisma.batch_jobs.update({ where: { id }, data: updateData, }); return { ...job, is_active: job.is_active ? "Y" : "N", } as BatchJob; } /** * 배치 작업 삭제 */ static async deleteBatchJob(id: number): Promise { await prisma.batch_jobs.delete({ where: { id }, }); } /** * 배치 작업 수동 실행 */ static async executeBatchJob(id: number): Promise { const job = await prisma.batch_jobs.findUnique({ where: { id }, }); if (!job) { throw new Error("배치 작업을 찾을 수 없습니다."); } if (!job.is_active) { throw new Error("비활성화된 배치 작업입니다."); } // 배치 실행 기록 생성 const execution = await prisma.batch_job_executions.create({ data: { job_id: id, execution_id: `exec_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, status: "RUNNING", start_time: new Date(), created_at: new Date(), }, }); // 실제 배치 작업 실행 로직은 여기에 구현 // 현재는 시뮬레이션으로 처리 setTimeout(async () => { try { // 배치 작업 시뮬레이션 await new Promise((resolve) => setTimeout(resolve, 5000)); await prisma.batch_job_executions.update({ where: { id: execution.id }, data: { status: "SUCCESS", end_time: new Date(), exit_message: "배치 작업이 성공적으로 완료되었습니다.", }, }); } catch (error) { await prisma.batch_job_executions.update({ where: { id: execution.id }, data: { status: "FAILED", end_time: new Date(), exit_message: error instanceof Error ? error.message : "알 수 없는 오류", }, }); } }, 0); return { ...execution, execution_status: execution.status as any, started_at: execution.start_time, completed_at: execution.end_time, error_message: execution.exit_message, } as BatchExecution; } /** * 배치 실행 목록 조회 */ static async getBatchExecutions(jobId?: number): Promise { const whereCondition: any = {}; if (jobId) { whereCondition.job_id = jobId; } const executions = await prisma.batch_job_executions.findMany({ where: whereCondition, orderBy: { start_time: "desc" }, // include 제거 - 관계가 정의되지 않음 }); return executions.map((exec: any) => ({ ...exec, execution_status: exec.status, started_at: exec.start_time, completed_at: exec.end_time, error_message: exec.exit_message, })) as BatchExecution[]; } /** * 배치 모니터링 정보 조회 */ static async getBatchMonitoring(): Promise { const totalJobs = await prisma.batch_jobs.count(); const activeJobs = await prisma.batch_jobs.count({ where: { is_active: "Y" }, }); const runningExecutions = await prisma.batch_job_executions.count({ where: { status: "RUNNING" }, }); const recentExecutions = await prisma.batch_job_executions.findMany({ where: { created_at: { gte: new Date(Date.now() - 24 * 60 * 60 * 1000), // 최근 24시간 }, }, orderBy: { start_time: "desc" }, take: 10, // include 제거 - 관계가 정의되지 않음 }); const successCount = await prisma.batch_job_executions.count({ where: { status: "SUCCESS", start_time: { gte: new Date(Date.now() - 24 * 60 * 60 * 1000), }, }, }); const failedCount = await prisma.batch_job_executions.count({ where: { status: "FAILED", start_time: { gte: new Date(Date.now() - 24 * 60 * 60 * 1000), }, }, }); return { total_jobs: totalJobs, active_jobs: activeJobs, running_jobs: runningExecutions, failed_jobs_today: failedCount, successful_jobs_today: successCount, recent_executions: recentExecutions.map((exec: any) => ({ ...exec, execution_status: exec.status, started_at: exec.start_time, completed_at: exec.end_time, error_message: exec.exit_message, })) as BatchExecution[], }; } }