-
Notifications
You must be signed in to change notification settings - Fork 3
refactor: add submit prepare, ready #159
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
Conversation
Walkthrough코드 제출 프로세스가 두 단계로 분리되었습니다. 먼저 Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Controller
participant Service
participant Queue
Client->>Controller: POST /problems/{id}/submit-prepare
Controller->>Service: prepareSubmission(problemId, authUser)
Service->>Service: 세션 키 생성, Lock 획득, 테스트케이스 조회
Service-->>Controller: SubmitResponse(sessionKey, testcaseIds)
Controller-->>Client: SubmitResponse(sessionKey, testcaseIds)
Client->>Controller: POST /problems/{id}/submit-ready (sessionKey, languageId, sourceCode)
Controller->>Service: enqueueCodeSubmission(problemId, request, authUser)
Service->>Queue: SubmissionMessage.of(request, problemId, userId)
Service-->>Controller: (void)
Controller-->>Client: 200 OK
Suggested reviewers
Poem
✨ Finishing Touches
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. 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)
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: 3
🧹 Nitpick comments (2)
src/main/resources/templates/test-submit.html (2)
1074-1076:onReady기본값 지정으로 호출 안전성 확보외부에서
onReady생략 시undefined체크를 반복할 필요가 없습니다. 기본 파라미터로 빈 함수 제공을 권장합니다.-function initWebSocket(sessionKey, onReady) { +function initWebSocket(sessionKey, onReady = () => {}) {
1098-1104: WebSocket 연결 실패에 대한 사용자 알림 부재현재 실패 시
console.error만 찍고 끝납니다. 채점 결과 영역에 오류 메시지를 표시하거나 재시도 버튼을 제공해 사용자가 문제를 인지할 수 있도록 해 주세요. 예시로judgeEl.textContent = 'WebSocket 연결 실패';정도만 추가해도 UX 가 크게 개선됩니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/main/java/org/ezcode/codetest/application/submission/dto/request/submission/CodeSubmitRequest.java(1 hunks)src/main/java/org/ezcode/codetest/application/submission/service/SubmissionService.java(2 hunks)src/main/java/org/ezcode/codetest/infrastructure/event/dto/submission/SubmissionMessage.java(2 hunks)src/main/java/org/ezcode/codetest/presentation/submission/SubmissionController.java(1 hunks)src/main/resources/templates/test-submit.html(8 hunks)src/test/java/org/ezcode/codetest/application/submission/SubmissionServiceTest.java(4 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: thezz9
PR: ezcode-my/backend#73
File: src/main/resources/templates/submit-test.html:135-135
Timestamp: 2025-06-18T11:41:58.457Z
Learning: src/main/resources/templates/submit-test.html 파일은 테스트용 파일로, isCorrect 값의 하드코딩은 의도적이며 사용자가 UI 요소를 통해 정답/오답 상태를 선택할 수 있도록 개선 예정입니다.
Learnt from: thezz9
PR: ezcode-my/backend#30
File: src/main/java/org/ezcode/codetest/application/submission/service/SubmissionService.java:44-46
Timestamp: 2025-06-04T13:12:17.636Z
Learning: SubmissionService에서 "2 10" 입력값과 "12" 기대출력이 하드코딩되어 있는 것은 테스트 단계의 의도적인 구현이며, 추후 Problem 엔티티의 실제 테스트케이스로 대체 예정입니다.
Learnt from: thezz9
PR: ezcode-my/backend#36
File: src/main/java/org/ezcode/codetest/application/submission/dto/request/compile/CodeCompileRequest.java:5-9
Timestamp: 2025-06-06T07:52:58.941Z
Learning: CodeCompileRequest 레코드의 필드명(source_code, language_id)은 Java camelCase 컨벤션 대신 snake_case를 사용하는데, 이는 Judge0 API의 반환 값 형식에 맞추기 위한 의도적인 설계 결정이다.
Learnt from: thezz9
PR: ezcode-my/backend#75
File: src/main/java/org/ezcode/codetest/application/submission/aop/CodeReviewLockAspect.java:25-41
Timestamp: 2025-06-19T06:37:57.845Z
Learning: User thezz9 tends to skip validation for scenarios they consider unlikely to occur, but is willing to implement defensive programming practices when suggested for code robustness.
Learnt from: thezz9
PR: ezcode-my/backend#114
File: src/main/java/org/ezcode/codetest/infrastructure/github/GitHubApiClient.java:93-96
Timestamp: 2025-06-28T02:04:24.957Z
Learning: User thezz9 sometimes temporarily uses less secure or inconsistent exception handling (like RuntimeException with raw error bodies) for debugging purposes when error messages are being hidden in the normal application flow, but acknowledges this as technical debt and fixes it once debugging is complete.
Learnt from: thezz9
PR: ezcode-my/backend#132
File: src/main/java/org/ezcode/codetest/infrastructure/github/GitHubContentBuilder.java:72-72
Timestamp: 2025-07-02T09:39:31.475Z
Learning: User thezz9 prefers to proceed with breaking changes to path structures when it improves the organization, rather than maintaining backward compatibility or implementing migration strategies.
Learnt from: thezz9
PR: ezcode-my/backend#114
File: src/main/java/org/ezcode/codetest/infrastructure/github/GitHubApiClient.java:159-165
Timestamp: 2025-06-28T02:03:38.693Z
Learning: User thezz9's service (ezcode) targets Korean users exclusively ("찐 한국인밖에 안 옴"), so Korean language hardcoding in commit messages and UI elements is intentional and appropriate for their use case.
src/main/java/org/ezcode/codetest/application/submission/dto/request/submission/CodeSubmitRequest.java (1)
Learnt from: thezz9
PR: ezcode-my/backend#36
File: src/main/java/org/ezcode/codetest/application/submission/dto/request/compile/CodeCompileRequest.java:5-9
Timestamp: 2025-06-06T07:52:58.941Z
Learning: CodeCompileRequest 레코드의 필드명(source_code, language_id)은 Java camelCase 컨벤션 대신 snake_case를 사용하는데, 이는 Judge0 API의 반환 값 형식에 맞추기 위한 의도적인 설계 결정이다.
src/main/java/org/ezcode/codetest/presentation/submission/SubmissionController.java (1)
Learnt from: NCookies
PR: ezcode-my/backend#17
File: src/main/java/org/ezcode/codetest/presentation/problemmanagement/ProblemAdminController.java:25-25
Timestamp: 2025-06-02T06:57:37.929Z
Learning: 이 프로젝트에서는 아직 Spring Security가 적용되지 않아서 @PreAuthorize 어노테이션이 주석 처리되어 있음. Spring Security 도입 전까지는 권한 검증 어노테이션들이 비활성화 상태임.
src/main/resources/templates/test-submit.html (2)
Learnt from: thezz9
PR: ezcode-my/backend#73
File: src/main/resources/templates/submit-test.html:135-135
Timestamp: 2025-06-18T11:41:58.457Z
Learning: src/main/resources/templates/submit-test.html 파일은 테스트용 파일로, isCorrect 값의 하드코딩은 의도적이며 사용자가 UI 요소를 통해 정답/오답 상태를 선택할 수 있도록 개선 예정입니다.
Learnt from: NCookies
PR: ezcode-my/backend#69
File: src/test/java/org/ezcode/codetest/domain/community/service/DiscussionVoteDomainServiceTest.java:115-119
Timestamp: 2025-06-17T11:22:40.147Z
Learning: `VoteResult`의 `prevVoteType` 필드는 UP 요청이 반복될 때 알림 도배를 방지하기 위한 목적으로 사용됩니다. 투표 취소(NONE) 시나리오에서는 알림 도배 방지 로직이 필요하지 않으므로, `prevVoteType`을 실제 이전 값으로 설정할 필요가 없습니다.
src/test/java/org/ezcode/codetest/application/submission/SubmissionServiceTest.java (8)
Learnt from: Kimminu7
PR: ezcode-my/backend#133
File: src/test/java/org/ezcode/codetest/domain/problem/service/ProblemDomainServiceTest.java:92-99
Timestamp: 2025-07-02T12:05:54.895Z
Learning: ProblemDomainService의 removeProblem 메서드는 DB에서 Problem을 삭제한 후 Elasticsearch에서도 해당 ProblemSearchDocument를 찾아서 삭제합니다. 만약 Elasticsearch에서 문서를 찾지 못하면 ProblemException(PROBLEM_NOT_FOUND)을 던지므로, 테스트에서는 problem.getId()와 searchRepository.findById() 모두 적절하게 mock해야 합니다.
Learnt from: chat26666
PR: ezcode-my/backend#31
File: src/main/java/org/ezcode/codetest/domain/problem/service/ProblemDomainService.java:25-27
Timestamp: 2025-06-04T15:11:19.343Z
Learning: In ProblemDomainService, when saving problems to both database and Elasticsearch, maintain transactional consistency by allowing rollback if either save operation fails. Data integrity between DB and ES is prioritized over availability - if Elasticsearch save fails, the entire transaction should roll back to prevent data inconsistency.
Learnt from: thezz9
PR: ezcode-my/backend#36
File: src/main/java/org/ezcode/codetest/domain/submission/dto/SubmissionData.java:47-58
Timestamp: 2025-06-06T07:59:41.806Z
Learning: SubmissionData.withAggregatedStats() 메서드에서 testCaseList는 상위 프로세스(base() 메서드의 problemInfo.testcaseList())에서 이미 null 체크가 처리되어 오므로 추가적인 null 체크가 불필요함
Learnt from: chat26666
PR: ezcode-my/backend#67
File: src/main/java/org/ezcode/codetest/application/game/play/GamePlayUseCase.java:117-124
Timestamp: 2025-06-16T17:19:46.167Z
Learning: In GamePlayUseCase.java, the user temporarily returns BattleLog domain object directly for testing/verification purposes with plans to convert to DTO later during development.
Learnt from: thezz9
PR: ezcode-my/backend#30
File: src/main/java/org/ezcode/codetest/application/submission/service/SubmissionService.java:44-46
Timestamp: 2025-06-04T13:12:17.636Z
Learning: SubmissionService에서 "2 10" 입력값과 "12" 기대출력이 하드코딩되어 있는 것은 테스트 단계의 의도적인 구현이며, 추후 Problem 엔티티의 실제 테스트케이스로 대체 예정입니다.
Learnt from: thezz9
PR: ezcode-my/backend#73
File: src/main/resources/templates/submit-test.html:135-135
Timestamp: 2025-06-18T11:41:58.457Z
Learning: src/main/resources/templates/submit-test.html 파일은 테스트용 파일로, isCorrect 값의 하드코딩은 의도적이며 사용자가 UI 요소를 통해 정답/오답 상태를 선택할 수 있도록 개선 예정입니다.
Learnt from: thezz9
PR: ezcode-my/backend#98
File: src/main/java/org/ezcode/codetest/application/submission/dto/event/SubmissionErrorEvent.java:17-22
Timestamp: 2025-06-25T01:24:30.773Z
Learning: JudgeClient에서 모든 예외를 SubmissionException으로 래핑해서 넘길 계획이므로, SubmissionErrorEvent.resolveCode() 메서드의 캐스팅은 안전할 예정임.
Learnt from: thezz9
PR: ezcode-my/backend#120
File: src/main/java/org/ezcode/codetest/infrastructure/judge0/Judge0Client.java:58-64
Timestamp: 2025-06-30T10:10:07.449Z
Learning: Judge0Client에서 Reactor의 retryWhen() 재시도가 모두 실패했을 때 발생하는 RetryExhaustedException은 package-private 클래스라서 직접 import할 수 없으므로, 부모 클래스인 IllegalStateException을 catch해서 COMPILE_TIMEOUT으로 매핑하는 것이 필요한 해결책이다.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (9)
src/main/java/org/ezcode/codetest/application/submission/dto/request/submission/CodeSubmitRequest.java (1)
19-22: 세션 키 필드 추가가 적절하게 구현되었습니다.새로운
sessionKey필드가 기존 필드들과 일관된 패턴으로 추가되었고, 적절한 유효성 검증과 한국어 메시지가 포함되어 있습니다. 두 단계 제출 프로세스에 필요한 필드가 올바르게 추가되었습니다.src/main/java/org/ezcode/codetest/infrastructure/event/dto/submission/SubmissionMessage.java (1)
18-26: 팩토리 메서드 구현이 잘 되어 있습니다.
SubmissionMessage.of()정적 팩토리 메서드가 적절하게 구현되어 있습니다.CodeSubmitRequest로부터 필요한 필드들을 추출하여 새로운 인스턴스를 생성하는 로직이 명확하고, 코드의 가독성과 유지보수성을 향상시킵니다.src/main/java/org/ezcode/codetest/application/submission/service/SubmissionService.java (2)
58-68: 제출 준비 메서드가 잘 구현되었습니다.락 획득, 세션 키 생성, 테스트케이스 조회 로직이 명확하게 분리되어 있습니다. 단일 책임 원칙을 잘 따르고 있어 코드의 유지보수성이 향상되었습니다.
70-74: 큐 등록 메서드가 단순하고 명확합니다.
SubmissionMessage.of()팩토리 메서드를 사용하여 메시지 생성이 간소화되었고, 메서드의 책임이 큐 등록에만 집중되어 있어 좋습니다.src/main/java/org/ezcode/codetest/presentation/submission/SubmissionController.java (2)
35-43: 제출 준비 엔드포인트가 잘 구현되었습니다.새로운
/submit-prepare엔드포인트가 명확하게 정의되어 있고, 서비스 계층의prepareSubmission()메서드를 적절히 호출하여 세션 키와 테스트케이스를 반환합니다.
45-75: 제출 완료 엔드포인트 변경이 적절합니다.엔드포인트 경로가
/submit-ready로 변경되었고, 반환 타입이ResponseEntity<Void>로 수정되어 두 단계 제출 프로세스의 역할 분리가 명확해졌습니다. OpenAPI 문서도 적절히 업데이트되었습니다.src/test/java/org/ezcode/codetest/application/submission/SubmissionServiceTest.java (3)
129-147: 제출 준비 테스트가 잘 구현되었습니다.새로운
prepareSubmissionSuccess()테스트가 락 획득, 세션 키 생성, 테스트케이스 조회 로직을 적절히 검증하고 있습니다. 모킹 전략과 검증 로직이 명확하게 구성되어 있습니다.
149-167: 큐 등록 테스트가 단순화되어 개선되었습니다.리팩토링된
enqueueCodeSubmission()메서드의 단순화된 책임에 맞게 테스트도 큐 메시지 등록에만 집중하도록 개선되었습니다. 불필요한 모킹이 제거되어 테스트가 더 명확해졌습니다.
271-284: 실패 케이스 테스트가 적절히 업데이트되었습니다.
prepareSubmissionFailed()테스트가 락 획득 실패 시나리오를 정확히 검증하고 있으며, 예외 타입과 메시지 검증이 적절하게 구현되어 있습니다.
| throw new SubmissionException(SubmissionExceptionCode.ALREADY_JUDGING); | ||
| } | ||
|
|
||
| String sessionKey = authUser.getId() + "_" + UUID.randomUUID(); |
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.
💡 Verification agent
🧩 Analysis chain
세션 키 생성 방식 검토 권장
현재 세션 키 생성 방식(userId + "_" + UUID.randomUUID())은 기본적으로 안전하지만, 동시성 환경에서의 유일성 보장을 위해 추가 검증이 필요할 수 있습니다.
다음 스크립트로 세션 키 생성 방식의 사용 현황을 확인하세요:
🏁 Script executed:
#!/bin/bash
# 세션 키 생성 패턴과 관련된 코드를 검색합니다.
rg -A 3 -B 3 "sessionKey.*UUID" --type java
rg -A 3 -B 3 "UUID\.randomUUID" --type javaLength of output: 6023
세션 키 생성 로직 강화 검토 요청
프로젝트 전역에서 UUID.randomUUID() 기반 세션 키 생성은 SubmissionService.java 64행에서만 사용되고 있음을 확인했습니다.
현재 userId + "_" + UUID.randomUUID() 방식은 충돌 확률이 극히 낮지만, 동시성 환경에서는 중복 키가 생성될 가능성을 완전히 배제할 수 없으므로 유일성 보장을 위한 추가 검증이 필요합니다.
제안 사항:
- 재생성 루프(do–while)로 중복 키 검증 후 재생성 로직 추가
- ULID, Snowflake 등 충돌 방지에 특화된 ID 생성 라이브러리 도입
- Spring Session, JWT 등 검증된 세션 관리 프레임워크 사용
예시:
String sessionKey;
do {
sessionKey = authUser.getId() + "_" + UUID.randomUUID();
} while (sessionRepository.existsByKey(sessionKey));🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/application/submission/service/SubmissionService.java
at line 64, the current session key generation using userId + "_" +
UUID.randomUUID() lacks a uniqueness check which may cause collisions in
concurrent environments. Modify the code to include a do-while loop that
generates a session key and checks its existence in the session repository,
regenerating if a duplicate is found. Alternatively, consider integrating a
collision-resistant ID generator like ULID or Snowflake, or use a robust session
management framework such as Spring Session or JWT for better uniqueness
guarantees.
| try { | ||
| const res = await fetch(`/api/problems/${pid}/submit-ws`, { | ||
| const res = await fetch(`/api/problems/${pid}/submit-prepare`, { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| ...tokenHeader() | ||
| }, | ||
| body: JSON.stringify(payload) | ||
| }); | ||
| const resp = await res.json(); |
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.
submit-prepare 호출 시 불필요한 Content-Type: application/json 헤더 제거 필요
바디가 없는 POST 요청에 Content-Type: application/json 헤더를 넣으면 서버(특히 Spring MVC)는 빈 JSON 파싱을 시도하다가 HttpMessageNotReadableException 을 던질 수 있습니다. 실제 바디가 필요 없다면 헤더를 제거하거나, 바디(JSON {})를 전달해 주세요.
- headers: {
- 'Content-Type': 'application/json',
- ...tokenHeader()
- },
+ headers: {
+ ...tokenHeader()
+ },📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| try { | |
| const res = await fetch(`/api/problems/${pid}/submit-ws`, { | |
| const res = await fetch(`/api/problems/${pid}/submit-prepare`, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| ...tokenHeader() | |
| }, | |
| body: JSON.stringify(payload) | |
| }); | |
| const resp = await res.json(); | |
| try { | |
| const res = await fetch(`/api/problems/${pid}/submit-prepare`, { | |
| method: 'POST', | |
| headers: { | |
| ...tokenHeader() | |
| }, | |
| }); | |
| const resp = await res.json(); |
🤖 Prompt for AI Agents
In src/main/resources/templates/test-submit.html around lines 962 to 970, the
POST request to `/api/problems/${pid}/submit-prepare` includes a 'Content-Type:
application/json' header without a request body, which can cause server errors.
Remove the 'Content-Type' header from the request headers or add an empty JSON
body '{}' to the fetch call to prevent the server from attempting to parse a
non-existent JSON body.
| initWebSocket(sessionKey, async () => { | ||
| renderInitSlots(testcaseIds); | ||
|
|
||
| await fetch(`/api/problems/${pid}/submit-ready`, { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| ...tokenHeader() | ||
| }, | ||
| body: JSON.stringify({ | ||
| sessionKey, | ||
| languageId, | ||
| sourceCode | ||
| }) | ||
| }); | ||
| }); |
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
submit-ready 요청 실패 시 UI 피드백·예외 처리 누락
onReady 콜백 내부에서 fetch 결과를 확인하지 않아 4xx/5xx 응답, 네트워크 오류가 발생해도 사용자에게 아무런 안내가 되지 않습니다. 최소한 res.ok 체크와 try/catch 를 추가해 주세요.
- initWebSocket(sessionKey, async () => {
- renderInitSlots(testcaseIds);
-
- await fetch(`/api/problems/${pid}/submit-ready`, {
+ initWebSocket(sessionKey, async () => {
+ renderInitSlots(testcaseIds);
+
+ try {
+ const readyRes = await fetch(`/api/problems/${pid}/submit-ready`, {
...
- });
+ });
+ if (!readyRes.ok) {
+ judgeEl.textContent = `채점 큐 등록 실패 (HTTP ${readyRes.status})`;
+ return;
+ }
+ } catch (e) {
+ console.error(e);
+ judgeEl.textContent = '채점 큐 등록 중 오류 발생';
+ }
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| initWebSocket(sessionKey, async () => { | |
| renderInitSlots(testcaseIds); | |
| await fetch(`/api/problems/${pid}/submit-ready`, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| ...tokenHeader() | |
| }, | |
| body: JSON.stringify({ | |
| sessionKey, | |
| languageId, | |
| sourceCode | |
| }) | |
| }); | |
| }); | |
| initWebSocket(sessionKey, async () => { | |
| renderInitSlots(testcaseIds); | |
| try { | |
| const readyRes = await fetch(`/api/problems/${pid}/submit-ready`, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| ...tokenHeader() | |
| }, | |
| body: JSON.stringify({ | |
| sessionKey, | |
| languageId, | |
| sourceCode | |
| }) | |
| }); | |
| if (!readyRes.ok) { | |
| judgeEl.textContent = `채점 큐 등록 실패 (HTTP ${readyRes.status})`; | |
| return; | |
| } | |
| } catch (e) { | |
| console.error(e); | |
| judgeEl.textContent = '채점 큐 등록 중 오류 발생'; | |
| } | |
| }); |
🤖 Prompt for AI Agents
In src/main/resources/templates/test-submit.html around lines 979 to 994, the
fetch call inside the onReady callback does not handle errors or check the
response status. To fix this, wrap the fetch call in a try/catch block and check
if the response's ok property is true. If not, provide appropriate UI feedback
or error handling to inform the user of the failure.
Summary by CodeRabbit
신규 기능
/problems/{problemId}/submit-prepare)가 추가되었습니다.기능 개선
/submit-ws에서/submit-ready로 변경되었습니다.버그 수정
테스트