Skip to content

Commit c2bcb30

Browse files
authored
[BACKEND] 호환성 체크 비동기 구조 개선 및 SSE 흐름 로깅 추가 (#109)
- @async("compatibilityCheckExecutor") 기반으로 호환성 체크 비동기 진입점 정리 - 서비스 내부에서 compatibilityCheckExecutor 스레드풀로 10개 검사 병렬 실행 - Controller 단의 CompletableFuture.runAsync 사용 제거 및 Future 체인으로 완료/에러 처리 - CompatibilityCheckService/CompatibilityController에 스레드명 포함 로그 추가 - 요청 수신, checkCompatibility 시작 - 검사 결과 콜백 호출 시점 - SSE result/completed/error 이벤트 전송 시점 - SSE 스트림이 비동기 스레드에서 바로 전송되는지 확인 가능하도록 구조 개선
1 parent b0bb4cb commit c2bcb30

File tree

2 files changed

+135
-101
lines changed

2 files changed

+135
-101
lines changed

backend/src/main/java/com/cmg/comtogether/compatibility/controller/CompatibilityController.java

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ public class CompatibilityController {
3434
public ResponseEntity<SseEmitter> checkCompatibility(
3535
@Valid @RequestBody CompatibilityCheckRequestDto requestDto
3636
) {
37+
log.info("[CompatibilityController] /compatibility/check 요청 수신, thread={}", Thread.currentThread().getName());
38+
3739
SseEmitter emitter = new SseEmitter(300000L); // 5분 타임아웃
3840

3941
// 초기 연결 확인
@@ -48,44 +50,57 @@ public ResponseEntity<SseEmitter> checkCompatibility(
4850
}
4951

5052
// 비동기로 호환성 체크 실행
51-
CompletableFuture.runAsync(() -> {
52-
try {
53-
compatibilityCheckService.checkCompatibility(
54-
requestDto.getItems(),
55-
result -> {
56-
try {
57-
// JSON을 포맷팅하여 가독성 향상
58-
String formattedJson = objectMapper.writerWithDefaultPrettyPrinter()
59-
.writeValueAsString(result);
60-
61-
// 각 검사 항목 완료 시 SSE로 전송 (포맷팅된 JSON 사용)
62-
emitter.send(SseEmitter.event()
63-
.name("result")
64-
.data(formattedJson));
65-
} catch (IOException e) {
66-
log.error("SSE 전송 실패", e);
67-
emitter.completeWithError(e);
68-
}
69-
}
70-
).join();
53+
CompletableFuture<Void> future = compatibilityCheckService.checkCompatibility(
54+
requestDto.getItems(),
55+
result -> {
56+
try {
57+
log.info(
58+
"[CompatibilityController] SSE result 이벤트 전송 준비: id={}, name={}, result={}, status={}, thread={}",
59+
result.getCheckId(),
60+
result.getCheckName(),
61+
result.getResult(),
62+
result.getStatus(),
63+
Thread.currentThread().getName()
64+
);
65+
66+
// JSON을 포맷팅하여 가독성 향상
67+
String formattedJson = objectMapper.writerWithDefaultPrettyPrinter()
68+
.writeValueAsString(result);
7169

72-
// 모든 검사 완료
70+
// 각 검사 항목 완료 시 SSE로 전송 (포맷팅된 JSON 사용)
71+
emitter.send(SseEmitter.event()
72+
.name("result")
73+
.data(formattedJson));
74+
} catch (IOException e) {
75+
log.error("SSE 전송 실패", e);
76+
emitter.completeWithError(e);
77+
}
78+
}
79+
);
80+
81+
future.thenRun(() -> {
82+
try {
83+
log.info("[CompatibilityController] SSE completed 이벤트 전송, thread={}", Thread.currentThread().getName());
7384
emitter.send(SseEmitter.event()
7485
.name("completed")
7586
.data("모든 호환성 검사가 완료되었습니다."));
7687
emitter.complete();
77-
78-
} catch (Exception e) {
79-
log.error("호환성 체크 중 오류 발생", e);
80-
try {
81-
emitter.send(SseEmitter.event()
82-
.name("error")
83-
.data("호환성 체크 중 오류가 발생했습니다: " + e.getMessage()));
84-
} catch (IOException ioException) {
85-
log.error("에러 메시지 전송 실패", ioException);
86-
}
88+
} catch (IOException e) {
89+
log.error("SSE 완료 이벤트 전송 실패", e);
8790
emitter.completeWithError(e);
8891
}
92+
}).exceptionally(ex -> {
93+
log.error("호환성 체크 중 오류 발생", ex);
94+
try {
95+
log.info("[CompatibilityController] SSE error 이벤트 전송, thread={}", Thread.currentThread().getName());
96+
emitter.send(SseEmitter.event()
97+
.name("error")
98+
.data("호환성 체크 중 오류가 발생했습니다: " + ex.getMessage()));
99+
} catch (IOException ioException) {
100+
log.error("에러 메시지 전송 실패", ioException);
101+
}
102+
emitter.completeWithError(ex);
103+
return null;
89104
});
90105

91106
// 연결 종료 시 처리

0 commit comments

Comments
 (0)