diff --git a/src/main/java/com/interplug/qcast/batch/JobLauncherController.java b/src/main/java/com/interplug/qcast/batch/JobLauncherController.java index f9a904d0..438bb19e 100644 --- a/src/main/java/com/interplug/qcast/batch/JobLauncherController.java +++ b/src/main/java/com/interplug/qcast/batch/JobLauncherController.java @@ -1,7 +1,5 @@ package com.interplug.qcast.batch; -import java.time.Duration; -import java.time.LocalDateTime; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -23,7 +21,8 @@ import org.springframework.web.bind.annotation.RestController; @RequiredArgsConstructor @Slf4j public class JobLauncherController { - private final Map jobs; + private final Map jobs; // 여러 Job을 주입받도록 변경 + private final JobLauncher jobLauncher; private final JobExplorer jobExplorer; @@ -35,188 +34,207 @@ public class JobLauncherController { // 현재 실행 중인 Job 추적을 위한 Set private final Set runningJobs = ConcurrentHashMap.newKeySet(); - /** * 특정 Job을 매핑으로 실행하는 메소드 + * + * @param jobName + * @return + * @throws JobInstanceAlreadyCompleteException + * @throws JobExecutionAlreadyRunningException + * @throws JobParametersInvalidException + * @throws JobRestartException */ - @GetMapping("/batch/job/{jobName}") - public Map launchJob(@PathVariable String jobName) { + @GetMapping("/batch/job/{jobName}") // Path Variable로 jobName을 받음 + public Map launchJob(@PathVariable String jobName) + throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, + JobParametersInvalidException, JobRestartException { + + Job job = jobs.get(jobName); - Map resultMap = new HashMap<>(); - + Map resultMap = new HashMap(); if (job == null) { + // return "Job " + jobName + " not found"; resultMap.put("code", "FAILED"); - resultMap.put("message", "Job " + jobName + " not found"); + resultMap.put("message", "Job" + jobName + " not found"); return resultMap; } // 실행 중인 Job 확인 if (runningJobs.contains(jobName) || isJobRunning(jobName)) { - resultMap.put("code", "ALREADY_RUNNING"); - resultMap.put("message", "Job " + jobName + " is already running"); + log.warn("Job {} is already running, skipping execution", jobName); + resultMap.put("code", "FAILED"); + resultMap.put("message", "Job "+ jobName +" is already running, skipping execution"); return resultMap; } - try { - runningJobs.add(jobName); - JobParameters jobParameters = new JobParametersBuilder() - .addString("jobName", jobName) - .addDate("time", new Date()) - .toJobParameters(); + JobParameters jobParameters = new JobParametersBuilder().addString("jobName", jobName) + .addDate("time", new Date()).toJobParameters(); - JobExecution jobExecution = jobLauncher.run(job, jobParameters); + JobExecution jobExecution = jobLauncher.run(job, jobParameters); - BatchStatus status = jobExecution.getStatus(); - ExitStatus exitStatus = jobExecution.getExitStatus(); - resultMap.put("code", status.toString()); - resultMap.put("message", exitStatus.getExitDescription()); - } catch (JobExecutionAlreadyRunningException e) { - resultMap.put("code", "ALREADY_RUNNING"); - resultMap.put("message", "Job " + jobName + " is already running"); - } catch (Exception e) { - resultMap.put("code", "FAILED"); - resultMap.put("message", "Error: " + e.getMessage()); - } finally { - runningJobs.remove(jobName); - } + BatchStatus status = jobExecution.getStatus(); + ExitStatus exitStatus = jobExecution.getExitStatus(); + resultMap.put("code", status.toString()); + resultMap.put("message", exitStatus.getExitDescription()); + + + // return "Job " + jobName + " started"; return resultMap; } /** * Q.CAST 판매점 / 사용자 / 즐겨찾기 / 노출 아이템 동기화 배치 + * + */ - @Scheduled(cron = "0 30 23 * * *") - public String storeAdditionalJob() { + // @Scheduled(cron = "*/5 * * * * *") + @Scheduled(cron = "0 50 23 * * *") + public String storeAdditionalJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + return executeScheduledJob("storeAdditionalJob"); + } /** * 아이템 동기화 배치 + * + */ @Scheduled(cron = "0 30 02 * * *") - public String materialJob() { + public String materialJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + return executeScheduledJob("materialJob"); + } /** * BOM 아이템 동기화 배치 + * + */ @Scheduled(cron = "0 40 02 * * *") - public String bomJob() { + public String bomJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + return executeScheduledJob("bomJob"); + } /** * 영업사원 동기화 배치 + * + */ @Scheduled(cron = "0 40 03 * * *") - public String businessChargerJob() { + public String businessChargerJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + return executeScheduledJob("businessChargerJob"); + } /** * 관리자 유저 동기화 배치 + * + */ - @Scheduled(cron = "0 0 01 * * *") - public String adminUserJob() { + @Scheduled(cron = "0 30 01 * * *") + public String adminUserJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + return executeScheduledJob("adminUserJob"); + } /** * 가격 동기화 배치 + * + */ - @Scheduled(cron = "0 30 0 * * *") // 시간 조정: 00:30 - public String priceJob() { + @Scheduled(cron = "0 20 00 * * *") + public String priceJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + return executeScheduledJob("priceJob"); + } /** * 공통코드 M_COMM_H, M_COMM_L 동기화 배치 + * + */ @Scheduled(cron = "0 10 03 * * *") - public String commonCodeJob() { + public String commonCodeJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + return executeScheduledJob("commonCodeJob"); + } /** * Q.CAST 견적특이사항 / 아이템 표시, 미표시 동기화 배치 + * + */ - @Scheduled(cron = "0 45 23 * * *") // 시간 조정: 23:45 - public String specialNoteDispItemAdditionalInfoJob() { + @Scheduled(cron = "0 30 23 * * *") + public String specialNoteDispItemAdditionalInfoJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { return executeScheduledJob("specialNoteDispItemAdditionalJob"); + } /** * Plan Confrim 동기화 배치 + * + */ @Scheduled(cron = "0 05 04 * * *") - public String planConfirmJob() { + public String planConfirmJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + return executeScheduledJob("planConfirmJob"); + } /** * 견적서 전송 동기화 배치 + * + */ @Scheduled(cron = "0 20 04 * * *") - public String estimateSyncJob() { + public String estimateSyncJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + return executeScheduledJob("estimateSyncJob"); + } /** * 공통 스케줄러 실행 메소드 */ - private String executeScheduledJob(String jobName) { - // 1. 가장 먼저 스케줄러 설정 확인 - if (!"Y".equals(scheduler) && !"materialJob".equals(jobName) && !"commonCodeJob".equals(jobName)) { - log.info("Scheduler disabled, skipping job {}", jobName); - return "Scheduler disabled"; - } - - // 2. Job 존재 확인 + private String executeScheduledJob(String jobName) throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { Job job = jobs.get(jobName); if (job == null) { log.error("Job {} not found", jobName); return "Job " + jobName + " not found"; } - // 3. 다른 Job 실행 중인지 확인 - if (isAnyJobRunning()) { - log.warn("Another job is running, skipping job {}", jobName); - return "Another job is running"; + if (!"Y".equals(scheduler) + && !"materialJob".equals(jobName) + && !"commonCodeJob".equals(jobName)) { + log.info("Scheduler disabled, skipping job {}", jobName); + return "Scheduler disabled"; } - // 4. 같은 Job이 실행 중인지 확인 + // 실행 중인 Job 확인 if (runningJobs.contains(jobName) || isJobRunning(jobName)) { - log.warn("Job {} is already running", jobName); + log.warn("Job {} is already running, skipping execution", jobName); return "Job already running"; } - // 5. Job 실행 - try { - runningJobs.add(jobName); - log.info("Starting job {}", jobName); + JobParameters jobParameters = + new JobParametersBuilder().addDate("time", new Date()).toJobParameters(); - JobParameters jobParameters = new JobParametersBuilder() - .addDate("time", new Date()) - .toJobParameters(); + jobLauncher.run(job, jobParameters); - JobExecution jobExecution = jobLauncher.run(job, jobParameters); - log.info("Job {} started successfully", jobName); - return "OK"; - - } catch (JobExecutionAlreadyRunningException e) { - log.warn("Job {} is already running: {}", jobName, e.getMessage()); - return "Job already running"; - } catch (Exception e) { - log.error("Error executing job {}: {}", jobName, e.getMessage()); - return "Error: " + e.getMessage(); - } finally { - runningJobs.remove(jobName); - } + return jobName+ " executed successfully"; } /** @@ -240,75 +258,4 @@ public class JobLauncherController { return false; } } - - /** - * 실행 중인 Job이 있는지 확인 - */ - private boolean isAnyJobRunning() { - String[] jobNames = {"storeAdditionalJob", "materialJob", "bomJob", "businessChargerJob", - "adminUserJob", "priceJob", "commonCodeJob", "specialNoteDispItemAdditionalJob", - "planConfirmJob", "estimateSyncJob"}; - - return Arrays.stream(jobNames) - .anyMatch(this::isJobRunning); - } - - /** - * 현재 실행 중인 Job 목록 조회 - */ - @GetMapping("/batch/running-jobs") - public Map getRunningJobs() { - Map result = new HashMap<>(); - result.put("runningJobs", new ArrayList<>(runningJobs)); - - Map jobStatuses = new HashMap<>(); - String[] jobNames = {"storeAdditionalJob", "materialJob", "bomJob", "businessChargerJob", - "adminUserJob", "priceJob", "commonCodeJob", "specialNoteDispItemAdditionalJob", - "planConfirmJob", "estimateSyncJob"}; - - for (String jobName : jobNames) { - jobStatuses.put(jobName, getJobStatus(jobName)); - } - - result.put("jobStatuses", jobStatuses); - return result; - } - - /** - * 특정 Job의 상태 정보 조회 - */ - private Map getJobStatus(String jobName) { - Map jobStatus = new HashMap<>(); - - try { - List jobInstances = jobExplorer.findJobInstancesByJobName(jobName, 0, 1); - if (jobInstances.isEmpty()) { - jobStatus.put("status", "NEVER_EXECUTED"); - return jobStatus; - } - - JobInstance latestJobInstance = jobInstances.get(0); - List jobExecutions = jobExplorer.getJobExecutions(latestJobInstance); - - if (!jobExecutions.isEmpty()) { - JobExecution latestExecution = jobExecutions.get(0); - jobStatus.put("status", latestExecution.getStatus().toString()); - jobStatus.put("startTime", latestExecution.getStartTime()); - jobStatus.put("endTime", latestExecution.getEndTime()); - - // Duration 계산 (LocalDateTime용) - if (latestExecution.getEndTime() != null && latestExecution.getStartTime() != null) { - Duration duration = Duration.between(latestExecution.getStartTime(), latestExecution.getEndTime()); - jobStatus.put("durationSeconds", duration.getSeconds()); - jobStatus.put("durationMillis", duration.toMillis()); - } - } - - } catch (Exception e) { - jobStatus.put("status", "ERROR"); - jobStatus.put("error", e.getMessage()); - } - - return jobStatus; - } -} \ No newline at end of file +}