development/Spring Boot
Spring @Async 환경에서 MultipartFile "파일을 찾을 수 없음" 에러 해결하기
root@soni
2025. 8. 16. 18:34
Spring Boot에서 파일 업로드 기능을 구현하던 중, 비동기 처리를 위해 @Async 어노테이션을 사용했을 때 다음과 같은 에러가 발생했습니다.
java.io.FileNotFoundException: /tmp/tomcat.xxx/work/Tomcat/localhost/ROOT/upload_xxx.tmp (No such file or directory)
또는
java.lang.IllegalStateException: The temporary upload location is not valid
문제 발생 원인
1. HTTP 요청 생명주기와 MultipartFile
Spring에서 MultipartFile은 HTTP 요청의 생명주기에 의존합니다.
HTTP 요청 시작 → MultipartFile 임시 저장 → 요청 처리 → HTTP 응답 완료 → 임시 파일 자동 삭제
2. @Async 메서드의 실행 타이밍
@Async 어노테이션이 붙은 메서드는 별도의 스레드 풀에서 실행되며, 호출 즉시 반환됩니다.
public void processFilesAsync(MultipartFile imageFile, MultipartFile videoFile) {
uploadAsync(imageFile, videoFile); // 비동기 호출 후 즉시 반환
} // HTTP 응답 완료 → MultipartFile 임시 파일 삭제
@Async
public void uploadAsync(MultipartFile imageFile, MultipartFile videoFile) {
// 실제 실행은 이후에 발생 (임시 파일이 이미 삭제된 상태)
}
3. 타이밍 문제
- HTTP 요청 처리: MultipartFile이 임시 디렉토리에 저장됨
- 컨트롤러 응답: HTTP 응답이 즉시 반환됨
- 임시 파일 정리: Spring이 MultipartFile의 임시 저장소를 자동으로 삭제
- @Async 실행: 별도 스레드에서 실행되지만 이미 파일이 삭제된 상태
해결 방법
1. MultipartFile을 File 객체로 사전 변환
public void processFilesAsync(MultipartFile imageFile, MultipartFile videoFile) throws IOException {
// HTTP 요청이 유효한 동안 File 객체로 변환
File savedImageFile = fileStorageHelper.saveToTemp(imageFile);
File savedVideoFile = fileStorageHelper.saveToTemp(videoFile);
// 이제 안전하게 비동기 처리
uploadAsync(savedImageFile, savedVideoFile);
}
@Async
public void uploadAsync(File imageFile, File videoFile) {
// File 객체로 안전하게 접근 가능
uploadToCloud(imageFile);
uploadToCloud(videoFile);
}
2. FileStorageHelper 구현
public File saveToTemp(MultipartFile multipartFile) throws IOException {
String uniqueFilename = UUID.randomUUID().toString() + getFileExtension(multipartFile.getOriginalFilename());
Path targetPath = Paths.get("/tmp/uploads").resolve(uniqueFilename);
multipartFile.transferTo(targetPath.toFile());
return targetPath.toFile();
}
해결 후 실행 흐름
- HTTP 요청 수신
- MultipartFile → File 변환 (안전한 위치에 저장)
- HTTP 응답 반환
- MultipartFile 임시 파일 자동 삭제 (문제없음)
- @Async 메서드 실행 (File 객체로 안전하게 접근)
- 처리 완료 후 임시 File 객체들 수동 삭제
추가 고려사항
메모리 효율성
- MultipartFile은 파일 내용을 메모리에 보관
- File 객체는 디스크 기반으로 메모리 효율적
Thread Safety
- MultipartFile은 thread-safe하지 않을 수 있음
- File 객체는 여러 스레드에서 안전하게 접근 가능
에러 처리
- 파일 변환 과정에서 발생할 수 있는 IOException 처리
- 임시 파일 정리 로직의 예외 처리
Spring의 @Async와 MultipartFile을 함께 사용할 때는 HTTP 요청의 생명주기를 고려해야 합니다. 비동기 처리 전에 MultipartFile을 안전한 File 객체로 변환하는 것이 핵심 해결책입니다.
이 방법을 통해 파일 업로드의 안정성을 확보하고, 대용량 파일 처리 시에도 메모리 효율성을 유지할 수 있습니다.