331 lines
15 KiB
Java
331 lines
15 KiB
Java
package com.snp.batch.global.controller;
|
|
|
|
import com.snp.batch.global.dto.JobExecutionDto;
|
|
import com.snp.batch.global.dto.JobLaunchRequest;
|
|
import com.snp.batch.global.dto.ScheduleRequest;
|
|
import com.snp.batch.global.dto.ScheduleResponse;
|
|
import com.snp.batch.service.BatchService;
|
|
import com.snp.batch.service.ScheduleService;
|
|
import io.swagger.v3.oas.annotations.Operation;
|
|
import io.swagger.v3.oas.annotations.Parameter;
|
|
import io.swagger.v3.oas.annotations.enums.Explode;
|
|
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
|
import io.swagger.v3.oas.annotations.enums.ParameterStyle;
|
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
|
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.springdoc.core.annotations.ParameterObject;
|
|
import org.springframework.http.ResponseEntity;
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
@Slf4j
|
|
@RestController
|
|
@RequestMapping("/api/batch")
|
|
@RequiredArgsConstructor
|
|
@Tag(name = "Batch Management API", description = "배치 작업 실행 및 스케줄 관리 API")
|
|
public class BatchController {
|
|
|
|
private final BatchService batchService;
|
|
private final ScheduleService scheduleService;
|
|
|
|
@Operation(summary = "배치 작업 실행", description = "지정된 배치 작업을 즉시 실행합니다. 쿼리 파라미터로 Job Parameters 전달 가능")
|
|
@ApiResponses(value = {
|
|
@ApiResponse(responseCode = "200", description = "작업 실행 성공"),
|
|
@ApiResponse(responseCode = "500", description = "작업 실행 실패")
|
|
})
|
|
@PostMapping("/jobs/{jobName}/execute")
|
|
public ResponseEntity<Map<String, Object>> executeJob(
|
|
@Parameter(description = "실행할 배치 작업 이름", required = true, example = "sampleProductImportJob")
|
|
@PathVariable String jobName,
|
|
@Parameter(description = "Job Parameters (동적 파라미터)", required = false, example = "?param1=value1¶m2=value2")
|
|
@RequestParam(required = false) Map<String, String> params) {
|
|
log.info("Received request to execute job: {} with params: {}", jobName, params);
|
|
try {
|
|
Long executionId = batchService.executeJob(jobName, params);
|
|
return ResponseEntity.ok(Map.of(
|
|
"success", true,
|
|
"message", "Job started successfully",
|
|
"executionId", executionId
|
|
));
|
|
} catch (Exception e) {
|
|
log.error("Error executing job: {}", jobName, e);
|
|
return ResponseEntity.internalServerError().body(Map.of(
|
|
"success", false,
|
|
"message", "Failed to start job: " + e.getMessage()
|
|
));
|
|
}
|
|
}
|
|
|
|
@Operation(summary = "배치 작업 실행", description = "지정된 배치 작업을 즉시 실행합니다. 쿼리 파라미터로 Job Parameters 전달 가능")
|
|
@ApiResponses(value = {
|
|
@ApiResponse(responseCode = "200", description = "작업 실행 성공"),
|
|
@ApiResponse(responseCode = "500", description = "작업 실행 실패")
|
|
})
|
|
@PostMapping("/jobs/{jobName}/executeJobTest")
|
|
public ResponseEntity<Map<String, Object>> executeJobTest(
|
|
@Parameter( description = "실행할 배치 작업 이름", required = true,example = "sampleProductImportJob")
|
|
@PathVariable String jobName,
|
|
@ParameterObject JobLaunchRequest request
|
|
) {
|
|
Map<String, String> params = new HashMap<>();
|
|
if (request.getStartDate() != null) params.put("startDate", request.getStartDate());
|
|
if (request.getStopDate() != null) params.put("stopDate", request.getStopDate());
|
|
|
|
log.info("Executing job: {} with params: {}", jobName, params);
|
|
|
|
try {
|
|
Long executionId = batchService.executeJob(jobName, params);
|
|
return ResponseEntity.ok(Map.of(
|
|
"success", true,
|
|
"message", "Job started successfully",
|
|
"executionId", executionId
|
|
));
|
|
} catch (Exception e) {
|
|
log.error("Error executing job: {}", jobName, e);
|
|
return ResponseEntity.internalServerError().body(Map.of(
|
|
"success", false,
|
|
"message", "Failed to start job: " + e.getMessage()
|
|
));
|
|
}
|
|
}
|
|
|
|
@Operation(summary = "배치 작업 목록 조회", description = "등록된 모든 배치 작업 목록을 조회합니다")
|
|
@ApiResponses(value = {
|
|
@ApiResponse(responseCode = "200", description = "조회 성공")
|
|
})
|
|
@GetMapping("/jobs")
|
|
public ResponseEntity<List<String>> listJobs() {
|
|
log.info("Received request to list all jobs");
|
|
List<String> jobs = batchService.listAllJobs();
|
|
return ResponseEntity.ok(jobs);
|
|
}
|
|
|
|
@Operation(summary = "배치 작업 실행 이력 조회", description = "특정 배치 작업의 실행 이력을 조회합니다")
|
|
@ApiResponses(value = {
|
|
@ApiResponse(responseCode = "200", description = "조회 성공")
|
|
})
|
|
@GetMapping("/jobs/{jobName}/executions")
|
|
public ResponseEntity<List<JobExecutionDto>> getJobExecutions(
|
|
@Parameter(description = "배치 작업 이름", required = true, example = "sampleProductImportJob")
|
|
@PathVariable String jobName) {
|
|
log.info("Received request to get executions for job: {}", jobName);
|
|
List<JobExecutionDto> executions = batchService.getJobExecutions(jobName);
|
|
return ResponseEntity.ok(executions);
|
|
}
|
|
|
|
@GetMapping("/executions/{executionId}")
|
|
public ResponseEntity<JobExecutionDto> getExecutionDetails(@PathVariable Long executionId) {
|
|
log.info("Received request to get execution details for: {}", executionId);
|
|
try {
|
|
JobExecutionDto execution = batchService.getExecutionDetails(executionId);
|
|
return ResponseEntity.ok(execution);
|
|
} catch (Exception e) {
|
|
log.error("Error getting execution details: {}", executionId, e);
|
|
return ResponseEntity.notFound().build();
|
|
}
|
|
}
|
|
|
|
@GetMapping("/executions/{executionId}/detail")
|
|
public ResponseEntity<com.snp.batch.global.dto.JobExecutionDetailDto> getExecutionDetailWithSteps(@PathVariable Long executionId) {
|
|
log.info("Received request to get detailed execution for: {}", executionId);
|
|
try {
|
|
com.snp.batch.global.dto.JobExecutionDetailDto detail = batchService.getExecutionDetailWithSteps(executionId);
|
|
return ResponseEntity.ok(detail);
|
|
} catch (Exception e) {
|
|
log.error("Error getting detailed execution: {}", executionId, e);
|
|
return ResponseEntity.notFound().build();
|
|
}
|
|
}
|
|
|
|
@PostMapping("/executions/{executionId}/stop")
|
|
public ResponseEntity<Map<String, Object>> stopExecution(@PathVariable Long executionId) {
|
|
log.info("Received request to stop execution: {}", executionId);
|
|
try {
|
|
batchService.stopExecution(executionId);
|
|
return ResponseEntity.ok(Map.of(
|
|
"success", true,
|
|
"message", "Execution stop requested"
|
|
));
|
|
} catch (Exception e) {
|
|
log.error("Error stopping execution: {}", executionId, e);
|
|
return ResponseEntity.internalServerError().body(Map.of(
|
|
"success", false,
|
|
"message", "Failed to stop execution: " + e.getMessage()
|
|
));
|
|
}
|
|
}
|
|
|
|
@Operation(summary = "스케줄 목록 조회", description = "등록된 모든 스케줄을 조회합니다")
|
|
@ApiResponses(value = {
|
|
@ApiResponse(responseCode = "200", description = "조회 성공")
|
|
})
|
|
@GetMapping("/schedules")
|
|
public ResponseEntity<Map<String, Object>> getSchedules() {
|
|
log.info("Received request to get all schedules");
|
|
List<ScheduleResponse> schedules = scheduleService.getAllSchedules();
|
|
return ResponseEntity.ok(Map.of(
|
|
"schedules", schedules,
|
|
"count", schedules.size()
|
|
));
|
|
}
|
|
|
|
@GetMapping("/schedules/{jobName}")
|
|
public ResponseEntity<ScheduleResponse> getSchedule(@PathVariable String jobName) {
|
|
log.debug("Received request to get schedule for job: {}", jobName);
|
|
try {
|
|
ScheduleResponse schedule = scheduleService.getScheduleByJobName(jobName);
|
|
return ResponseEntity.ok(schedule);
|
|
} catch (IllegalArgumentException e) {
|
|
// 스케줄이 없는 경우 - 정상적인 시나리오 (UI에서 존재 여부 확인용)
|
|
log.debug("Schedule not found for job: {} (정상 - 존재 확인)", jobName);
|
|
return ResponseEntity.notFound().build();
|
|
} catch (Exception e) {
|
|
log.error("Error getting schedule for job: {}", jobName, e);
|
|
return ResponseEntity.notFound().build();
|
|
}
|
|
}
|
|
|
|
@Operation(summary = "스케줄 생성", description = "새로운 배치 작업 스케줄을 등록합니다")
|
|
@ApiResponses(value = {
|
|
@ApiResponse(responseCode = "200", description = "생성 성공"),
|
|
@ApiResponse(responseCode = "500", description = "생성 실패")
|
|
})
|
|
@PostMapping("/schedules")
|
|
public ResponseEntity<Map<String, Object>> createSchedule(
|
|
@Parameter(description = "스케줄 생성 요청 데이터", required = true)
|
|
@RequestBody ScheduleRequest request) {
|
|
log.info("Received request to create schedule for job: {}", request.getJobName());
|
|
try {
|
|
ScheduleResponse schedule = scheduleService.createSchedule(request);
|
|
return ResponseEntity.ok(Map.of(
|
|
"success", true,
|
|
"message", "Schedule created successfully",
|
|
"data", schedule
|
|
));
|
|
} catch (Exception e) {
|
|
log.error("Error creating schedule for job: {}", request.getJobName(), e);
|
|
return ResponseEntity.internalServerError().body(Map.of(
|
|
"success", false,
|
|
"message", "Failed to create schedule: " + e.getMessage()
|
|
));
|
|
}
|
|
}
|
|
|
|
@PostMapping("/schedules/{jobName}/update")
|
|
public ResponseEntity<Map<String, Object>> updateSchedule(
|
|
@PathVariable String jobName,
|
|
@RequestBody Map<String, String> request) {
|
|
log.info("Received request to update schedule for job: {}", jobName);
|
|
try {
|
|
String cronExpression = request.get("cronExpression");
|
|
String description = request.get("description");
|
|
ScheduleResponse schedule = scheduleService.updateSchedule(jobName, cronExpression, description);
|
|
return ResponseEntity.ok(Map.of(
|
|
"success", true,
|
|
"message", "Schedule updated successfully",
|
|
"data", schedule
|
|
));
|
|
} catch (Exception e) {
|
|
log.error("Error updating schedule for job: {}", jobName, e);
|
|
return ResponseEntity.internalServerError().body(Map.of(
|
|
"success", false,
|
|
"message", "Failed to update schedule: " + e.getMessage()
|
|
));
|
|
}
|
|
}
|
|
|
|
@Operation(summary = "스케줄 삭제", description = "배치 작업 스케줄을 삭제합니다")
|
|
@ApiResponses(value = {
|
|
@ApiResponse(responseCode = "200", description = "삭제 성공"),
|
|
@ApiResponse(responseCode = "500", description = "삭제 실패")
|
|
})
|
|
@PostMapping("/schedules/{jobName}/delete")
|
|
public ResponseEntity<Map<String, Object>> deleteSchedule(
|
|
@Parameter(description = "배치 작업 이름", required = true)
|
|
@PathVariable String jobName) {
|
|
log.info("Received request to delete schedule for job: {}", jobName);
|
|
try {
|
|
scheduleService.deleteSchedule(jobName);
|
|
return ResponseEntity.ok(Map.of(
|
|
"success", true,
|
|
"message", "Schedule deleted successfully"
|
|
));
|
|
} catch (Exception e) {
|
|
log.error("Error deleting schedule for job: {}", jobName, e);
|
|
return ResponseEntity.internalServerError().body(Map.of(
|
|
"success", false,
|
|
"message", "Failed to delete schedule: " + e.getMessage()
|
|
));
|
|
}
|
|
}
|
|
|
|
@PostMapping("/schedules/{jobName}/toggle")
|
|
public ResponseEntity<Map<String, Object>> toggleSchedule(
|
|
@PathVariable String jobName,
|
|
@RequestBody Map<String, Boolean> request) {
|
|
log.info("Received request to toggle schedule for job: {}", jobName);
|
|
try {
|
|
Boolean active = request.get("active");
|
|
ScheduleResponse schedule = scheduleService.toggleScheduleActive(jobName, active);
|
|
return ResponseEntity.ok(Map.of(
|
|
"success", true,
|
|
"message", "Schedule toggled successfully",
|
|
"data", schedule
|
|
));
|
|
} catch (Exception e) {
|
|
log.error("Error toggling schedule for job: {}", jobName, e);
|
|
return ResponseEntity.internalServerError().body(Map.of(
|
|
"success", false,
|
|
"message", "Failed to toggle schedule: " + e.getMessage()
|
|
));
|
|
}
|
|
}
|
|
|
|
@GetMapping("/timeline")
|
|
public ResponseEntity<com.snp.batch.global.dto.TimelineResponse> getTimeline(
|
|
@RequestParam String view,
|
|
@RequestParam String date) {
|
|
log.info("Received request to get timeline: view={}, date={}", view, date);
|
|
try {
|
|
com.snp.batch.global.dto.TimelineResponse timeline = batchService.getTimeline(view, date);
|
|
return ResponseEntity.ok(timeline);
|
|
} catch (Exception e) {
|
|
log.error("Error getting timeline", e);
|
|
return ResponseEntity.internalServerError().build();
|
|
}
|
|
}
|
|
|
|
@GetMapping("/dashboard")
|
|
public ResponseEntity<com.snp.batch.global.dto.DashboardResponse> getDashboard() {
|
|
log.info("Received request to get dashboard data");
|
|
try {
|
|
com.snp.batch.global.dto.DashboardResponse dashboard = batchService.getDashboardData();
|
|
return ResponseEntity.ok(dashboard);
|
|
} catch (Exception e) {
|
|
log.error("Error getting dashboard data", e);
|
|
return ResponseEntity.internalServerError().build();
|
|
}
|
|
}
|
|
|
|
@GetMapping("/timeline/period-executions")
|
|
public ResponseEntity<List<JobExecutionDto>> getPeriodExecutions(
|
|
@RequestParam String jobName,
|
|
@RequestParam String view,
|
|
@RequestParam String periodKey) {
|
|
log.info("Received request to get period executions: jobName={}, view={}, periodKey={}", jobName, view, periodKey);
|
|
try {
|
|
List<JobExecutionDto> executions = batchService.getPeriodExecutions(jobName, view, periodKey);
|
|
return ResponseEntity.ok(executions);
|
|
} catch (Exception e) {
|
|
log.error("Error getting period executions", e);
|
|
return ResponseEntity.internalServerError().build();
|
|
}
|
|
}
|
|
}
|