-
Notifications
You must be signed in to change notification settings - Fork 0
[fix] 예외 처리 개선 #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[fix] 예외 처리 개선 #17
Conversation
Walkthrough이번 변경에서는 Discord 봇의 GCP 관련 명령 처리 로직과 GCP 서비스 내부에서 발생하는 예외를 포괄적으로 try-catch로 감싸고, 예외 발생 시 사용자에게 명확한 에러 메시지를 출력하도록 개선하였습니다. 또한 CI/CD 워크플로우 트리거 브랜치가 Changes
Sequence Diagram(s)sequenceDiagram
participant DiscordUser
participant GcpBotService
participant GcpService
DiscordUser->>GcpBotService: 슬래시 커맨드 실행 (예: start, stop 등)
GcpBotService->>GcpService: GCP API 호출 (try-catch로 감싸짐)
GcpService-->>GcpBotService: 성공 결과 또는 예외 throw
alt 예외 발생 시
GcpBotService-->>DiscordUser: "❌" + 에러 메시지로 응답
else 정상 처리
GcpBotService-->>DiscordUser: 정상 결과 메시지 응답
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~15 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Poem
Note 🔌 MCP (Model Context Protocol) integration is now available in Early Access!Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context. ✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🔭 Outside diff range comments (1)
src/main/java/com/gcp/domain/gcp/service/GcpService.java (1)
44-45: Optional 값 미존재 시 상세 메시지 누락
orElseThrow()에 아무 메시지도 전달하지 않아 토큰이 없을 때NoSuchElementException이 빈 메시지로 던져집니다. 호출측에 의미 있는 정보를 주기 위해 커스텀 예외나orElseThrow(() -> new RuntimeException("Google OAuth 토큰을 찾을 수 없습니다."))형태로 명시적 메시지를 포함해 주세요.
♻️ Duplicate comments (1)
src/main/java/com/gcp/domain/discord/service/GcpBotService.java (1)
197-221: deferReply() 후 catch 블록에서 reply() 사용앞서 지적한 것과 동일한 문제입니다. 모든
deferReply()블록의 예외 처리에서reply()대신getHook()사용으로 수정해 주세요.
🧹 Nitpick comments (3)
src/main/java/com/gcp/domain/gcp/service/GcpService.java (1)
186-190:@SneakyThrows불필요이 메서드는 내부에서 모든 예외를
catch하고 있으므로 Checked 예외 전파가 없습니다.@SneakyThrows를 제거해도 컴파일이 통과하니 어노테이션을 삭제해 코드 가독성을 높여주세요.src/main/java/com/gcp/domain/discord/service/GcpBotService.java (2)
129-135: 불필요한 이중 세미콜론
event.reply("❌ " + e.getMessage()).queue();;처럼 세미콜론이 두 번 들어가 있습니다. 빌드에는 영향 없지만 제거하여 가독성을 높여주세요.
170-175: 빈 리스트 상황에서 예외 사용VM이 없을 때
Exception을 던지고 여기서 잡아 “보유 중인 인스턴스가 없습니다.”를 응답하고 있습니다. 단순 비즈니스 결과를 예외로 표현하기보다 서비스 메서드가 빈 리스트를 반환하도록 하고 봇에서 그대로 메시지를 보여주는 편이 명확합니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
.github/workflows/deploy.yml(1 hunks)src/main/java/com/gcp/domain/discord/service/GcpBotService.java(2 hunks)src/main/java/com/gcp/domain/gcp/service/GcpService.java(12 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: kamillcream
PR: Cloudible/GCP#8
File: src/main/java/com/gcp/domain/gcp/service/GcpService.java:38-38
Timestamp: 2025-08-01T19:45:32.212Z
Learning: Discord 봇 서비스에서는 orElseThrow()로 예외를 던지는 것보다 Optional.isEmpty() 체크 후 사용자 친화적인 메시지를 직접 반환하는 것을 선호함. 특히 GcpService.java에서 Google OAuth 토큰 조회 실패 시 예외 대신 안내 메시지 반환이 더 적절함.
📚 Learning: 2025-08-01T19:45:32.212Z
Learnt from: kamillcream
PR: Cloudible/GCP#8
File: src/main/java/com/gcp/domain/gcp/service/GcpService.java:38-38
Timestamp: 2025-08-01T19:45:32.212Z
Learning: Discord 봇 서비스에서는 orElseThrow()로 예외를 던지는 것보다 Optional.isEmpty() 체크 후 사용자 친화적인 메시지를 직접 반환하는 것을 선호함. 특히 GcpService.java에서 Google OAuth 토큰 조회 실패 시 예외 대신 안내 메시지 반환이 더 적절함.
Applied to files:
src/main/java/com/gcp/domain/discord/service/GcpBotService.javasrc/main/java/com/gcp/domain/gcp/service/GcpService.java
🔇 Additional comments (3)
src/main/java/com/gcp/domain/gcp/service/GcpService.java (2)
268-271: 루프 중 한 프로젝트 실패 시 전체 중단
for루프 안에서 한 프로젝트 조회가 실패하면RuntimeException을 던져 전체 목록 조회가 중단됩니다. 장애가 난 프로젝트를 로그로만 남기고continue로 넘어가면 나머지 프로젝트 정보는 제공할 수 있습니다. 실패 허용(soft‐fail)이 더 적합한지 검토해 주세요.
372-375: 에러 응답 형식 불일치
Conflict시에는 문자열을 반환하면서 그 외 예외는 throw 하고 있습니다. 호출 측(GcpBotService)에서는 패턴이 혼재되어 처리 로직이 복잡해집니다. 동일한 기준(전부 예외, 혹은 전부 메시지 반환)으로 맞춰주세요..github/workflows/deploy.yml (1)
5-5: 메인 브랜치 배포 누락 가능성배포 트리거가
fix/#16-exception-handling-fix로 한정되어 있어 PR 병합 후main브랜치에서 CI/CD가 동작하지 않을 수 있습니다. 이후 운영 배포를 위해main도 포함하거나branches-ignore패턴을 사용하는 방안을 검토하세요.
| try{ | ||
| String vmName = getRequiredOption(event, "vm_name"); | ||
| event.deferReply().queue(); | ||
|
|
||
| List<String> logs = gcpService.getVmLogs(userId, guildId, vmName); | ||
| List<String> logs = gcpService.getVmLogs(userId, guildId, vmName); | ||
|
|
||
| if (logs.isEmpty()) { | ||
| event.getHook().sendMessage("📭 로그가 없습니다.").queue(); | ||
| return; | ||
| } | ||
| if (logs.isEmpty()) { | ||
| event.getHook().sendMessage("📭 로그가 없습니다.").queue(); | ||
| return; | ||
| } | ||
|
|
||
| for (String log : logs) { | ||
| event.getHook().sendMessage("```bash\n" + log + "\n```").queue(); | ||
| for (String log : logs) { | ||
| event.getHook().sendMessage("```bash\n" + log + "\n```").queue(); | ||
| } | ||
| } catch (RuntimeException e){ | ||
| event.reply("❌ " + e.getMessage()).queue(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
deferReply() 이후 오류 응답 방식 오류
event.deferReply() 호출 후에는 event.reply()를 다시 사용할 수 없습니다. 예외 발생 시
event.getHook().sendMessage("❌ " + e.getMessage()).queue();또는 editOriginal()로 응답을 수정해야 합니다. 동일 패턴이 firewall-list 등 다른 커맨드에도 있으니 함께 수정해 주세요.
🤖 Prompt for AI Agents
In src/main/java/com/gcp/domain/discord/service/GcpBotService.java around lines
146 to 162, after calling event.deferReply(), the code incorrectly uses
event.reply() in the catch block, which is not allowed. To fix this, replace
event.reply() with event.getHook().sendMessage() or use
event.getHook().editOriginal() to send the error message. Also, review and apply
the same fix to other commands like firewall-list that use this pattern.
| log.error("❌ VM 시작 오류", e); | ||
| throw new RuntimeException("Compute API (start) 호출 도중 에러 발생: ", e); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
중복적인 RuntimeException 래핑 패턴
모든 메서드에서 동일한 패턴으로 예외를 잡아 RuntimeException으로 다시 래핑하고 있습니다.
- 예외 유형별로 구분이 사라져 상위 계층에서 세밀한 분기 처리가 어렵습니다.
- 메시지가 한글 + 영문 혼용으로 중복되고 있어 유지보수가 힘듭니다.
서비스 전용 GcpApiException 같은 커스텀 런타임 예외를 정의하여 공통 정보를 담고, 필요 시 errorCode를 포함하도록 리팩터링을 권장합니다.
Also applies to: 76-79, 102-105, 169-172, 181-183, 198-204, 227-230, 268-271, 373-375, 418-420, 460-461, 486-487
🤖 Prompt for AI Agents
In src/main/java/com/gcp/domain/gcp/service/GcpService.java around lines 55-57
and similarly at lines 76-79, 102-105, 169-172, 181-183, 198-204, 227-230,
268-271, 373-375, 418-420, 460-461, and 486-487, the code repeatedly catches
exceptions and wraps them in RuntimeException with mixed language messages,
causing poor exception granularity and maintenance difficulty. Define a custom
runtime exception class named GcpApiException that can hold common error
information and optionally an errorCode. Replace all RuntimeException wrapping
with this custom exception, unify the error messages into a consistent format,
and use the custom exception to improve error handling and maintainability.
📌 PR 개요
✅ 변경사항
🔍 체크리스트
📎 관련 이슈
Closes #16
💬 기타 참고사항
Summary by CodeRabbit
버그 수정
기타