Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
package org.ezcode.codetest.application.submission.service;

import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

import org.ezcode.codetest.application.submission.aop.CodeReviewLock;
import org.ezcode.codetest.application.submission.dto.event.TestcaseListInitializedEvent;
import org.ezcode.codetest.application.submission.dto.event.payload.InitTestcaseListPayload;
import org.ezcode.codetest.application.submission.dto.request.review.CodeReviewRequest;
import org.ezcode.codetest.application.submission.dto.request.review.ReviewPayload;
import org.ezcode.codetest.application.submission.dto.response.review.CodeReviewResponse;
Expand All @@ -17,7 +13,6 @@
import org.ezcode.codetest.application.submission.port.ExceptionNotifier;
import org.ezcode.codetest.application.submission.port.LockManager;
import org.ezcode.codetest.application.submission.port.QueueProducer;
import org.ezcode.codetest.domain.problem.model.entity.Testcase;
import org.ezcode.codetest.domain.submission.exception.SubmissionException;
import org.ezcode.codetest.domain.submission.exception.code.SubmissionExceptionCode;
import org.ezcode.codetest.infrastructure.event.dto.submission.SubmissionMessage;
Expand All @@ -33,7 +28,6 @@
import org.ezcode.codetest.domain.user.model.entity.AuthUser;
import org.ezcode.codetest.domain.user.model.entity.User;
import org.ezcode.codetest.domain.user.service.UserDomainService;
import org.ezcode.codetest.infrastructure.event.dto.submission.response.InitTestcaseListResponse;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand Down Expand Up @@ -78,7 +72,6 @@ public void processSubmissionAsync(SubmissionMessage msg) {
try {
log.info("[Submission RUN] Thread = {}", Thread.currentThread().getName());
log.info("[큐 수신] SubmissionMessage.sessionKey: {}", msg.sessionKey());

SubmissionContext ctx = createSubmissionContext(msg);
judgementService.publishInitTestcases(ctx);
judgementService.runTestcases(ctx);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public void onMessage(MapRecord<String, String, String> message) {

try {
log.info("[컨슈머 수신] {}", msg.sessionKey());
Thread.sleep(6000);
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

❓ Verification inconclusive

임시 해결책으로 Thread.sleep 사용 - 향후 개선 필요

타이밍 이슈 해결을 위한 임시 방편으로 이해되지만, 다음 사항들을 고려해 주세요:

  1. 성능 영향: 블로킹 방식으로 처리량 저하 가능성
  2. 리소스 낭비: 스레드 풀의 스레드가 6초간 대기 상태로 유지
  3. 불확실성: 6초가 항상 충분한 시간인지 보장되지 않음

향후 개선 방안:

  • CompletableFuture.delayedExecutor() 사용한 비동기 지연 처리
  • Redis pub/sub 기반의 이벤트 동기화
  • 초기화 완료 신호를 확인하는 polling 메커니즘
// 향후 개선 예시 (비동기 지연 처리)
CompletableFuture.delayedExecutor(6, TimeUnit.SECONDS)
    .execute(() -> submissionService.processSubmissionAsync(msg));

Thread.sleep(6000) 제거 및 비동기 지연 처리 도입 필요

현재 Redis 스트림 메시지 컨슈머에서 Thread.sleep(6000)을 사용한 고정 대기는 다음 문제를 유발할 수 있습니다:

  • 성능 저하: 스레드가 블로킹되어 처리량 감소
  • 리소스 낭비: 스레드 풀이 불필요하게 점유
  • 불확실성: 6초가 항상 적절한 지점 보장 불가

아래와 같은 비동기 지연 처리 방식으로 교체를 권장합니다:

// CompletableFuture.delayedExecutor() 사용 예시
CompletableFuture
    .delayedExecutor(6, TimeUnit.SECONDS)
    .execute(() -> submissionService.processSubmissionAsync(msg));

또는 Redis pub/sub 이벤트 기반 동기화, 초기화 완료 신호 확인용 폴링 메커니즘 등으로 개선해 주세요.

[src/main/java/org/ezcode/codetest/infrastructure/event/listener/RedisJudgeQueueConsumer.java:39]

🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/infrastructure/event/listener/RedisJudgeQueueConsumer.java
at line 39, replace the blocking Thread.sleep(6000) call with a non-blocking
asynchronous delay using CompletableFuture.delayedExecutor to avoid thread
blocking and improve performance. Implement the delay by scheduling the
subsequent processing logic inside the delayedExecutor's execute method, or
alternatively use an event-driven or polling mechanism to handle synchronization
without fixed thread sleeps.

submissionService.processSubmissionAsync(msg);

log.info("[컨슈머 ACK] messageId={}", message.getId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,14 @@
import org.springframework.messaging.simp.SimpMessageType;

import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Component;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
@RequiredArgsConstructor
public class StompMessageService {
Expand Down Expand Up @@ -65,6 +62,7 @@ public void sendInitTestcases(
String principalName,
List<InitTestcaseListResponse> dataList
) {
log.info("init 발행");
messagingTemplate.convertAndSendToUser(
principalName,
SUBMISSION_DEST_PREFIX.formatted(sessionKey) + "/init",
Expand All @@ -77,6 +75,7 @@ public void sendTestcaseResultUpdate(
String principalName,
JudgeResultResponse data
) {
log.info("case 발행");
messagingTemplate.convertAndSendToUser(
principalName,
SUBMISSION_DEST_PREFIX.formatted(sessionKey) + "/case",
Expand All @@ -89,6 +88,7 @@ public void sendFinalResult(
String principalName,
SubmissionFinalResultResponse data
) {
log.info("final 발행");
messagingTemplate.convertAndSendToUser(
principalName,
SUBMISSION_DEST_PREFIX.formatted(sessionKey) + "/final",
Expand Down