Skip to content

Conversation

@Kimminu7
Copy link
Collaborator

@Kimminu7 Kimminu7 commented Jun 25, 2025


작업 내용

  • 트랜잭션 범위 내 외부 서비스 호출 처리
    하지 않으면, 문제점 3가지 발생
  1. S3 업로드 실패 시 DB 트랜잭션도 롤백됨
  2. S3 업로드 성공 후 DB 저장 실패 시 S3에 불필요한 파일 남음
  3. 트랜잭션이 오래 지속됨

변경 사항


트러블 슈팅


해결해야 할 문제

  • 수정과 삭제는 아직 되지 않음
  • 이게 확실한 이미지 파일인지 검증할 로직 필요.

참고 사항


코드 리뷰 전 확인 체크리스트

  • 불필요한 콘솔 로그, 주석 제거
  • 커밋 메시지 컨벤션 준수 (type : )
  • 기능 정상 동작 확인

Summary by CodeRabbit

  • 버그 수정

    • 문제 생성 시 이미지 업로드 실패에 대한 예외 처리 및 오류 로그가 추가되어 안정성이 향상되었습니다.
  • 기타

    • 문제 이미지 업로드 및 등록 과정이 분리되어 트랜잭션 관리가 개선되었습니다.

@coderabbitai
Copy link

coderabbitai bot commented Jun 25, 2025

Walkthrough

ProblemService 클래스에서 문제 이미지 업로드 로직이 분리되어, 이미지 업로드와 문제 엔티티 업데이트가 각각 별도의 트랜잭션에서 처리되도록 개선되었습니다. 업로드 실패 시 예외 처리와 로깅이 추가되었으며, 이미지 URL 추가를 위한 별도의 트랜잭션 메서드가 도입되었습니다.

Changes

파일/경로 변경 요약
src/main/java/org/ezcode/codetest/application/problem/service/ProblemService.java 이미지 업로드 및 문제 엔티티 업데이트 로직 분리, 예외 처리 및 로깅 추가, 신규 메서드(updateProblemWithImage) 도입

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant ProblemService
    participant S3
    participant DB

    Client->>ProblemService: createProblem()
    ProblemService->>DB: 문제 엔티티 저장
    ProblemService->>S3: uploadImageAfterTransaction()
    alt 업로드 성공
        ProblemService->>ProblemService: updateProblemWithImage()
        ProblemService->>DB: 이미지 URL로 문제 엔티티 업데이트
    else 업로드 실패
        ProblemService->>ProblemService: S3Exception 발생 및 로깅
    end
Loading

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • NCookies
  • pokerbearkr

Poem

🐰
이미지 업로드, 트랜잭션 분리
예외 처리 꼼꼼히, 로그도 챙기니
문제와 사진, 따로 또 같이
깔끔한 코드에 토끼도 방긋 웃지!
S3 바람 타고, 안정성 높여
오늘도 개발은 한 뼘 더!

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d7ecc3a and 5aeca65.

📒 Files selected for processing (1)
  • src/main/java/org/ezcode/codetest/application/problem/service/ProblemService.java (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (2)
src/main/java/org/ezcode/codetest/application/problem/service/ProblemService.java (2)

15-16: 필요한 예외 처리 import가 추가되었습니다.

S3 업로드 실패 시 적절한 예외 처리를 위한 import가 추가되어 좋습니다.


24-24: 로깅 지원이 추가되었습니다.

Lombok의 @Slf4j 어노테이션을 통한 로깅 지원 추가가 적절합니다.

Also applies to: 28-28

Comment on lines +105 to +112
private String uploadImageAfterTransaction(MultipartFile image, Long problemId) {
try {
return s3Uploader.upload(image, S3Directory.PROBLEM.getDir());
} catch (Exception e) {
log.error("Problem {} 이미지 업로드 실패", problemId, e);
throw new S3Exception(S3ExceptionCode.S3_UPLOAD_FAILED);
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

S3 업로드 메서드가 여전히 트랜잭션 내에서 호출됩니다.

메서드명이 uploadImageAfterTransaction이지만 실제로는 트랜잭션 내에서 호출되고 있습니다. 또한 업로드 실패 시 예외가 발생하면 전체 트랜잭션이 롤백됩니다.

진정한 트랜잭션 분리를 위해 다음 중 하나를 고려해보세요:

  1. 비동기 처리: S3 업로드를 별도 스레드에서 처리
  2. 트랜잭션 커밋 후 처리: @TransactionalEventListener를 활용한 이벤트 기반 처리
  3. 별도 서비스 분리: S3 업로드 전용 서비스를 만들어 @Transactional(propagation = Propagation.NOT_SUPPORTED) 적용
+@Async
+@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
+public void handleImageUpload(ProblemImageUploadEvent event) {
+    try {
+        String imageUrl = s3Uploader.upload(event.getImage(), S3Directory.PROBLEM.getDir());
+        updateProblemWithImage(event.getProblemId(), imageUrl);
+    } catch (Exception e) {
+        log.error("Problem {} 이미지 업로드 실패", event.getProblemId(), e);
+        // 업로드 실패 시 별도 처리 로직 (예: 재시도 큐에 추가)
+    }
+}

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/application/problem/service/ProblemService.java
around lines 105 to 112, the uploadImageAfterTransaction method is misleadingly
named because it is still called within a transaction, causing S3 upload
failures to trigger a transaction rollback. To fix this, refactor the code to
ensure the S3 upload happens outside the transaction by either making the upload
asynchronous, using @TransactionalEventListener to handle the upload after
transaction commit, or moving the upload logic to a separate service method
annotated with @Transactional(propagation = Propagation.NOT_SUPPORTED) to
suspend the transaction during upload.

Comment on lines +99 to +103
@Transactional
public void updateProblemWithImage(Long problemId, String imageUrl) {
Problem problem = problemDomainService.getProblem(problemId);
problem.addImage(imageUrl);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

트랜잭션 전파 설정이 필요합니다.

현재 메서드는 기존 트랜잭션에 참여하게 되어 별도의 트랜잭션으로 동작하지 않습니다. 진정한 트랜잭션 분리를 위해서는 전파 설정이 필요합니다.

다음과 같이 트랜잭션 전파 설정을 추가하는 것을 권장합니다:

-@Transactional
+@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateProblemWithImage(Long problemId, String imageUrl) {
    Problem problem = problemDomainService.getProblem(problemId);
    problem.addImage(imageUrl);
}
🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/application/problem/service/ProblemService.java
around lines 99 to 103, the updateProblemWithImage method is annotated with
@Transactional but lacks explicit propagation settings, causing it to join
existing transactions instead of running in a separate one. To fix this, add a
propagation attribute to the @Transactional annotation, such as
Propagation.REQUIRES_NEW, to ensure the method executes in its own transaction,
providing true transaction isolation.

Comment on lines +46 to +47
String imageUrl = uploadImageAfterTransaction(image, savedProblem.getId());
updateProblemWithImage(savedProblem.getId(), imageUrl);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

트랜잭션 범위 분리가 불완전합니다.

현재 구현에서는 여전히 S3 업로드가 데이터베이스 트랜잭션 내에서 호출되고 있어 PR 목표가 완전히 달성되지 않았습니다. uploadImageAfterTransactionupdateProblemWithImage 모두 @Transactional 메서드 내에서 호출되므로 여전히 같은 트랜잭션에 참여합니다.

다음과 같은 방식으로 트랜잭션을 완전히 분리하는 것을 권장합니다:

@Transactional
public ProblemDetailResponse createProblem(ProblemCreateRequest requestDto, MultipartFile image, AuthUser authUser) {
    User user = userDomainService.getUserById(authUser.getId());
    Problem problem = ProblemCreateRequest.toEntity(requestDto, user);
    Problem savedProblem = problemDomainService.createProblem(problem);
    
-   // 문제 이미지 있다면?
-   if (image != null && !image.isEmpty()) {
-       String imageUrl = uploadImageAfterTransaction(image, savedProblem.getId());
-       updateProblemWithImage(savedProblem.getId(), imageUrl);
-   }
    
    return ProblemDetailResponse.from(savedProblem);
}

+@Transactional
+public ProblemDetailResponse createProblemWithImage(ProblemCreateRequest requestDto, MultipartFile image, AuthUser authUser) {
+    ProblemDetailResponse response = createProblem(requestDto, null, authUser);
+    
+    if (image != null && !image.isEmpty()) {
+        String imageUrl = uploadImageAfterTransaction(image, response.id());
+        updateProblemWithImage(response.id(), imageUrl);
+    }
+    
+    return response;
+}

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/application/problem/service/ProblemService.java
around lines 46 to 47, the S3 image upload and database update are still
executed within the same transaction because both methods are called inside a
@Transactional method. To fully separate the transaction scope, refactor so that
the image upload happens outside any @Transactional method, and the
updateProblemWithImage method is called in a separate @Transactional context
after the upload completes. This may involve restructuring the service calls or
using a separate service bean to invoke the update method transactionally after
the upload.

@Kimminu7 Kimminu7 added the documentation Improvements or additions to documentation label Jun 25, 2025
@Kimminu7 Kimminu7 merged commit 61d0e6e into dev Jun 26, 2025
2 checks passed
@Kimminu7 Kimminu7 deleted the refactor/problemS3 branch June 26, 2025 01:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants