Skip to content

fix: 썸네일 큐 초과 시 성공한 업로드가 500으로 응답되는 문제 수정 - #108

Merged
hamtorygoals merged 1 commit into
developfrom
fix/86-thumbnail-queue-rejection-500
Jul 17, 2026
Merged

fix: 썸네일 큐 초과 시 성공한 업로드가 500으로 응답되는 문제 수정#108
hamtorygoals merged 1 commit into
developfrom
fix/86-thumbnail-queue-rejection-500

Conversation

@hamtorygoals

@hamtorygoals hamtorygoals commented Jul 17, 2026

Copy link
Copy Markdown
Member

Why

#86은 꽤 예전에 등록된 이슈라 현재도 유효한지 먼저 검증했고, 최근 변경들(썸네일 READY 정합성 수정 등)과는 무관하게 버그가 그대로 남아있는 걸 확인했습니다.

버그 상황: 업로드 완료 등록(PhotoUploadService.completeUpload())이 사진을 DB에 커밋한 직후, afterCommit() 콜백에서 각 사진의 썸네일 생성 작업을 thumbnailExecutor(ThreadPoolTaskExecutor, core=4/max=6/queue=100)에 제출합니다. 큐가 가득 차면 RejectedExecutionException이 나는데, 이 시점엔 이미 사진이 정상 커밋된 뒤라 예외가 그대로 전파되면 업로드는 성공했는데 응답만 500으로 깨지는 상태 불일치가 생깁니다. 같은 모임에서 여러 명이 몰아서 업로드하는 패턴이 자연스러운 서비스 특성상, 동시 사용자 5~6명만 겹쳐도 흔히 발생할 수 있는 상황이었습니다(이슈 원본의 벤치마크: 동시 사용자 3명만으로도 큐 56/100까지 참).

리뷰 과정에서 같은 결함이 복구 경로인 PhotoSweepScheduler.resubmitStaleThumbnailJobs()(5분마다 도는 재수거 스윕)에도 그대로 있는 걸 추가로 발견했습니다. 이 스케줄러는 원래 "큐 제출이 실패해도 사진은 PENDING으로 남아있으니 나중에 재수거된다"는 안전망 역할인데, 정작 그 스윕 자체가 같은 예외에 무방비해서, 큐가 지속적으로 가득 찬 상황에서는 스윕 배치의 첫 사진에서 루프가 중단되고 나머지 사진들이 그 사이클에서 조용히 누락됐습니다.

What changed / What improved

  • PhotoUploadService: thumbnailProcessingService.process() 호출을 try/catch로 감싸 RejectedExecutionException(Spring의 TaskRejectedException 포함)을 로그만 남기고 삼키도록 수정.
    • Before: 큐 초과 시 예외가 컨트롤러까지 전파 → 클라이언트는 500을 받지만 사진은 이미 DB에 존재하는 상태 불일치.
    • After: 큐 초과여도 201 성공 응답 그대로 반환. 사진은 기본값인 PENDING으로 남고, 스윕이 나중에 재수거해 썸네일을 생성. 배치 업로드(최대 20장) 중 한 장이 거부돼도 나머지 장은 계속 정상 제출됨(이전엔 첫 장에서 예외가 나면 루프 자체가 중단돼 나머지도 제출 시도조차 못 했음).
  • PhotoSweepScheduler: 같은 예외를 사진 단위 try/catch로 처리하도록 수정(같은 클래스의 다른 두 메서드가 이미 쓰던 패턴과 통일).
    • Before: 스윕 배치 중 한 사진에서 큐 초과 예외가 나면 나머지 사진은 그 사이클에서 재제출 시도조차 안 됨(다음 사이클까지 지연).
    • After: 한 사진이 실패해도 배치의 나머지 사진은 계속 재제출됨.
  • API 응답 계약은 변경 없음 — 요청/응답 DTO, 엔드포인트, 정상 케이스 상태 코드 전부 기존과 동일. 프론트엔드 대응 불필요.
  • docs/architecture/backend-architecture.md 4.3절에 큐 초과 시 안전 처리 방식을 결정 기록으로 추가.

부하 재측정과 thumbnail.executor.queue-capacity 값 확정은 실측이 필요한 별도 작업이라 #107로 분리했습니다.

Test plan

  • 단위 테스트: PhotoUploadServiceTest — 큐 초과 시 afterCommit() 콜백이 예외를 전파하지 않음을 검증
  • 단위 테스트: PhotoSweepSchedulerTest — 한 사진이 큐 초과로 실패해도 나머지 사진은 계속 재제출됨을 검증
  • 통합 테스트: SharedAlbumPhotoUploadLimitIntegrationTest — 실제 Postgres + MockMvc로 큐 초과 상황에서도 완료등록 API가 201을 반환함을 확인
  • 전체 테스트 스위트 통과
  • develop과 병합 충돌 없음

Closes #86

🤖 Generated with Claude Code

thumbnailExecutor 큐가 가득 차면 afterCommit() 콜백에서 던진
RejectedExecutionException이 그대로 전파돼, 사진은 이미 커밋됐는데
응답만 500으로 깨지는 상태 불일치가 있었다. 예외를 잡아 로그만 남기고
PENDING 상태로 두면 PhotoSweepScheduler가 재수거하도록 수정.
PhotoSweepScheduler.resubmitStaleThumbnailJobs()도 같은 예외에
보호되어 있지 않아, 큐가 지속적으로 가득 찬 상황에서는 스윕 배치의
첫 사진에서 루프가 중단되고 나머지 사진들이 그 사이클에서 조용히
누락되는 동일한 결함이 있었다. 같은 방식으로 사진 단위 try/catch를
추가해 한 사진의 실패가 나머지 재제출을 막지 않도록 수정.
Closes #86
@hamtorygoals hamtorygoals self-assigned this Jul 17, 2026

@jaehunshin-git jaehunshin-git left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

검토 완료했습니다.

@hamtorygoals
hamtorygoals merged commit cc1b79c into develop Jul 17, 2026
2 checks passed
@jaehunshin-git
jaehunshin-git deleted the fix/86-thumbnail-queue-rejection-500 branch July 18, 2026 11:30
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.

[fix] 썸네일 큐 초과 시 성공한 업로드가 500으로 응답될 위험

2 participants