Skip to content

refactor: 영상 처리 방식을 메모리에서 디스크로 전환 #48

Merged
Woomin-Wang merged 1 commit into
mainfrom
refactor/video-disk-transfer
Apr 1, 2026
Merged

refactor: 영상 처리 방식을 메모리에서 디스크로 전환 #48
Woomin-Wang merged 1 commit into
mainfrom
refactor/video-disk-transfer

Conversation

@Woomin-Wang
Copy link
Copy Markdown
Contributor

📌 관련 이슈 (Related Issue)

📝 작업 내용 (Description)

MultipartFile.getBytes()로 영상 전체를 byte[]로 메모리에 적재하던 방식을 video.transferTo(path)를 사용해 디스크로 직접 전송하는 방식으로 전환했습니다.

  • AnswerService: byte[] 제거, createTempFile() 헬퍼 메서드로 추출
  • VideoAnswerAnalyzer.uploadToS3(): byte[] → Path 파라미터로 변경
  • FileUploader.upload(): byte[] → Path 기반으로 변경, RequestBody.fromFile() 사용
  • 미사용 upload(MultipartFile) 오버로드 제거
  • 비동기 호출 3개를 try 블록 밖으로 분리
  • 로그 prefix [VIDEO], [VIDEO-S3], [VIDEO-STT], [VIDEO-ANALYSIS] 로 통일

🔄 변경 유형 (Type of Change)

  • ✨ 새로운 기능 (feat)
  • 🐛 버그 수정 (fix)
  • 📝 문서 수정 (docs)
  • 💄 스타일 (style)
  • ♻️ 리팩토링 (refactor)
  • ✅ 테스트 (test)
  • 🔧 기타 (chore)

✅ 체크리스트 (Checklist)

  • 코드가 정상적으로 동작하는지 확인했습니다
  • 기존 테스트가 통과합니다
  • 필요한 경우 새로운 테스트를 추가했습니다

💬 추가 코멘트 (Additional Comments)

  • 임시 파일(createTempFile) 삭제 처리는 포함되지 않았습니다.
  • 세 비동기 작업이 모두 완료된 시점에 삭제해야 하므로 별도 이슈로 분리하여 처리할 예정입니다.

@Woomin-Wang Woomin-Wang merged commit 8c60ac0 into main Apr 1, 2026
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the video answer submission process to use file paths instead of byte arrays, which improves memory efficiency during file handling. The FileUploader has been simplified by removing unused methods, and VideoAnswerAnalyzer now includes more detailed logging for its asynchronous tasks. Feedback focuses on addressing a potential resource leak where temporary files are not deleted after processing, refining exception handling to be more specific, and ensuring consistent S3 key generation by using the UTC timezone.

Path videoPath = Files.createTempFile("video-", getExtension(video.getOriginalFilename()));
Files.write(videoPath, videoBytes);
log.info("[VIDEO] 영상 답변 처리 시작 - questionId: {}, memberId: {}", questionId, memberId);
Path videoPath = createTempFile(video);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

생성된 임시 파일(videoPath)이 삭제되지 않고 디스크에 남게 됩니다. 영상 파일은 용량이 크므로 누적될 경우 디스크 풀(Disk Full) 장애를 유발할 수 있습니다. 비동기 작업들이 모두 완료된 후 파일을 삭제하는 로직을 추가해야 합니다.

권장 방법:

  1. VideoAnswerAnalyzer의 메서드들이 CompletableFuture<Void>를 반환하도록 변경
  2. CompletableFuture.allOf(...).thenRun(() -> { ... 파일 삭제 ... })를 사용하여 모든 작업 완료 후 리소스를 정리

import io.wisoft.prepair.prepair_api.global.exception.ErrorCode;
import io.wisoft.prepair.prepair_api.repository.QuestionRepository;
import java.io.IOException;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

구체적인 예외 처리를 위해 IOException 임포트가 필요합니다.

Suggested change
import java.io.IOException;

Path videoPath = Files.createTempFile("video-", getExtension(video.getOriginalFilename()));
video.transferTo(videoPath);
return videoPath;
} catch (Exception e) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Exception 대신 구체적인 예외(IOException, IllegalStateException)를 캐치하는 것이 좋습니다. 이는 예기치 않은 런타임 예외를 방지하고 문제 발생 시 원인을 더 명확하게 파악할 수 있게 해줍니다.

Suggested change
} catch (Exception e) {
} catch (IOException | IllegalStateException e) {

String extension = getExtension(originalFilename);
public String upload(Path videoPath, String contentType, String email) {
String extension = getExtension(videoPath.getFileName().toString());
String key = "interview-video/" + email + "/" + LocalDate.now() + "/" + UUID.randomUUID() + extension;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

LocalDate.now()는 서버의 시스템 시간대에 의존합니다. 서비스의 일관성을 위해 UTC 시간대를 명시적으로 사용하는 것을 권장합니다.

Suggested change
String key = "interview-video/" + email + "/" + LocalDate.now() + "/" + UUID.randomUUID() + extension;
String key = "interview-video/" + email + "/" + java.time.LocalDate.now(java.time.ZoneOffset.UTC) + "/" + UUID.randomUUID() + extension;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor: 영상 처리 방식을 메모리에서 디스크로 전환

1 participant