반응형
안녕하세요,
오늘은 저번글에서 예시로 들었던 생성하는데 60분이상, 오랜 시간 걸리는 엑셀 생성 기능에 대해 알아보겠습니다,
로직은 제가 이전에 올렸던 엑셀 생성 글을 참고하여 기능을 구현하시기바라며, 해당 기능은 구현했으나 동기식으로 구현하였다는 가정하에 다음 내용을 진행하겠습니다.
해당 작업은 파일 생성에 오랜시간 걸리기때문에 사용자 경험과 시스템 성능 관점에서 비효율적일 가능성이 큽니다.
사용자가 웹 요청을 통해 이 작업을 실행할 경우, 서버는 해당 요청을 처리하느라 그동안 바쁘게 유지되고, 클라이언트는 응답을 기다리는 동안 아무것도 하지 못합니다.
이 문제를 해결하려면, 작업을 비동기 처리하고 사용자가 작업 진행 상태를 확인하거나 완료된 작업의 결과를 받을 수 있도록 설계해야 합니다.
비동기 처리 설계 방법
1. 비동기 작업 실행
- 요청을 받으면 엑셀 생성 작업을 비동기적으로 실행하고, 즉시 작업 ID를 반환합니다.
- 사용자는 반환된 작업 ID를 통해 작업 진행 상태를 확인할 수 있습니다.
2. 작업 상태 저장
- 작업 상태(예: 대기 중, 진행 중, 완료, 실패)를 저장할 데이터베이스 또는 인메모리 저장소를 준비합니다.
3. 결과 제공
- 작업이 완료되면 결과 파일(엑셀 파일)을 저장소에 저장하고, 사용자는 이를 다운로드할 수 있도록 링크를 제공합니다.
구현 단계
1. 비동기 작업 설정
@Async를 사용하여 엑셀 생성 작업을 비동기로 실행합니다.
@Service
public class ExcelService {
@Async
public CompletableFuture<String> generateExcel(Long jobId) {
try {
// 작업 상태를 '진행 중'으로 업데이트
JobStatusManager.updateStatus(jobId, "IN_PROGRESS");
// 60분이 걸리는 엑셀 생성 로직
Thread.sleep(3600000); // 60분 대기 (모의 작업)
String filePath = "/path/to/excel/file.xlsx";
// 작업 완료 후 상태 업데이트
JobStatusManager.updateStatus(jobId, "COMPLETED");
return CompletableFuture.completedFuture(filePath);
} catch (Exception e) {
// 실패 시 상태 업데이트
JobStatusManager.updateStatus(jobId, "FAILED");
return CompletableFuture.failedFuture(e);
}
}
}
2. 작업 요청 처리
사용자가 작업을 요청하면 작업 ID를 생성하고, 비동기 작업을 실행한 후 작업 ID를 반환합니다.
@RestController
@RequestMapping("/excel")
public class ExcelController {
private final ExcelService excelService;
public ExcelController(ExcelService excelService) {
this.excelService = excelService;
}
@PostMapping("/generate")
public ResponseEntity<Long> generateExcel() {
// 새로운 작업 ID 생성 및 상태 저장
Long jobId = JobStatusManager.createNewJob();
excelService.generateExcel(jobId);
return ResponseEntity.ok(jobId); // 작업 ID 반환
}
@GetMapping("/status/{jobId}")
public ResponseEntity<String> getJobStatus(@PathVariable Long jobId) {
String status = JobStatusManager.getStatus(jobId);
return ResponseEntity.ok(status);
}
@GetMapping("/download/{jobId}")
public ResponseEntity<Resource> downloadExcel(@PathVariable Long jobId) {
if ("COMPLETED".equals(JobStatusManager.getStatus(jobId))) {
String filePath = JobStatusManager.getFilePath(jobId);
File file = new File(filePath);
InputStreamResource resource = new InputStreamResource(new FileInputStream(file));
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + file.getName())
.contentLength(file.length())
.body(resource);
} else {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
}
}
}
3. 작업 상태 관리
작업 상태를 관리하기 위해 간단한 상태 관리 클래스를 구현합니다. 여기서는 인메모리 맵을 사용합니다.
@Component
public class JobStatusManager {
private static final Map<Long, String> jobStatusMap = new ConcurrentHashMap<>();
private static final Map<Long, String> jobFileMap = new ConcurrentHashMap<>();
private static final AtomicLong jobIdGenerator = new AtomicLong();
public static Long createNewJob() {
Long jobId = jobIdGenerator.incrementAndGet();
jobStatusMap.put(jobId, "PENDING");
return jobId;
}
public static void updateStatus(Long jobId, String status) {
jobStatusMap.put(jobId, status);
}
public static String getStatus(Long jobId) {
return jobStatusMap.getOrDefault(jobId, "UNKNOWN");
}
public static void setFilePath(Long jobId, String filePath) {
jobFileMap.put(jobId, filePath);
}
public static String getFilePath(Long jobId) {
return jobFileMap.get(jobId);
}
}
작동 흐름
- 엑셀 생성 요청: 사용자가 /excel/generate에 요청을 보냅니다.
- 새로운 작업 ID가 생성되고 작업이 비동기적으로 실행됩니다.
- 작업 ID가 클라이언트에 반환됩니다.
- 작업 상태 확인: 사용자는 /excel/status/{jobId}로 작업 상태를 확인합니다.
- 상태는 PENDING, IN_PROGRESS, COMPLETED, FAILED 중 하나입니다.
- 결과 다운로드: 작업이 완료되면 /excel/download/{jobId}로 엑셀 파일을 다운로드합니다.
이점
- 서버가 60분 동안 요청을 블로킹하지 않고 다른 작업도 동시에 처리할 수 있습니다.
- 사용자는 작업 상태를 실시간으로 확인하고, 필요 시 다운로드 링크를 통해 결과를 받을 수 있습니다.
- 시스템 자원을 효율적으로 관리하며 비동기 작업을 처리할 수 있습니다.
비동기 엑셀생성 처리에 대하여 알아보았습니다, 감사합니다.
반응형
'programming language > Java' 카테고리의 다른 글
Java _ Async를 이용한 비동기 처리방법 (0) | 2024.12.01 |
---|---|
intelliJ에서 vmOption 및 JavaProject 메모리 설정 (3) | 2024.11.20 |
Java _ 데이터를 엑셀 파일로 만들기 (2) | 2024.11.19 |
Java_ 엑셀 파일 시트별로 병합하기 (2) | 2024.11.18 |
보안) FileUtils를 이용한 업로드 확장자를 제한하는 방법 (0) | 2024.07.23 |