요새 날이 넘 춥네요..
안그래도 추운 날씨에 밖에 나가기가 무서워진 요즘..
Handle이 고장한 8톤 트럭,,도 아닌데, throws를 선언해도 처리되지 않았다며 우기는 Controller와 화해한 이야기 풉니다,,
1. 문제의 코드
@GetMapping("/touch")
Mono<?> touch(@RequestParam(name = "queue", defaultValue = "default") String queue,
@RequestParam(name = "user_id") Long userId,
ServerWebExchange exchange) throws NoSuchAlgorithmException {
return Mono.defer(() -> userQueueService.generateToken(queue, userId))
.map(token -> {
exchange.getResponse().addCookie(
ResponseCookie.from("user-queue-%s-token".formatted(queue), token)
.maxAge(Duration.ofSeconds(300))
.path("/")
.build()
);
return token;
});
}
public Mono<String> generateToken(final String queue, final Long userId) throws NoSuchAlgorithmException{
MessageDigest digest = MessageDigest.getInstance("SHA-256");
String input = "user-queue-%s-%d".formatted(queue, userId);
byte[] encodedHash = digest.digest(input.getBytes(StandardCharsets.UTF_8));
StringBuilder hexString = new StringBuilder();
for (byte b : encodedHash) {
hexString.append(String.format("%02x", b));
}
return Mono.just(hexString.toString());
}
2. 문제의 상황
generateToken 메서드는 SHA-256 암호화 알고리즘을 이용해서 토큰값을 생성합니다.
MessageDigest 클래스의 getInstance를 사용하려면 Checked Exception인 NoSuchAlgorithmException에 대한 처리를 해줘야 합니다.
generateToken()를 호출하는 "/touch" API 또한 NoSuchAlgorithmException이 발생한다고 throws를 적으면 NoSuchAlgorithmException이 Unhandled exception이라며 오류가 발생합니다^^!
3. 문제의 원인
Spring WebFlux에서 Mono 또는 Flux 내부에서 발생하는 Checked 예외는 반드시 Mono.error() 또는 onErrorResume() 등을 통해 처리해야 합니다.
⭐ 즉, 비동기 코드(WebFlux)에서는 throws가 먹히지 않고 Mono.error(e)를 사용해야 합니다.
4. 해결 방법
Mono.defer() 내부에서 예외를 처리
@GetMapping("/touch")
Mono<?> touch(@RequestParam(name = "queue", defaultValue = "default") String queue,
@RequestParam(name = "user_id") Long userId,
ServerWebExchange exchange) {
return Mono.defer(() -> {
try {
return userQueueService.generateToken(queue, userId);
} catch (NoSuchAlgorithmException e) {
return Mono.error(e);
}
}).map(token -> {
exchange.getResponse().addCookie(
ResponseCookie.from("user-queue-%s-token".formatted(queue), token)
.maxAge(Duration.ofSeconds(300))
.path("/")
.build()
);
return token;
});
}
Checked 예외를 Unchecked 예외로 변경
public Mono<String> generateToken(final String queue, final Long userId) {
MessageDigest digest = null;
try {
digest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
String input = "user-queue-%s-%d".formatted(queue, userId);
byte[] encodedHash = digest.digest(input.getBytes(StandardCharsets.UTF_8));
StringBuilder hexString = new StringBuilder();
for (byte b : encodedHash) {
hexString.append(String.format("%02x", b));
}
return Mono.just(hexString.toString());
}
🤗 정리
예외 유형 | Mono에서 처리 방식 |
Checked Exception (NoSuchAlgorithmException) | Mono.error(e)를 써야 Mono 체인에서 처리 가능 |
Unchecked Exception (RuntimeException) |
따로 감싸지 않아도 Mono 체인에서 자동으로 예외 감지 |
🚀 결론
예외를 클라이언트에게 전달할 필요가 있을 경우 → Mono.error(e)로 감싸서 처리하는 것이 좋음
500 에러로 내보내면 충분할 경우 → try-catch 후 RuntimeException 던지는 것이 더 간결하고 좋음
📑
참고 자료
Chat GPT
https://fastcampus.co.kr/dev_online_traffic_data
9개 프로젝트로 경험하는 대용량 트래픽 & 데이터 처리 완벽 마스터하기 | 패스트캠퍼스
실무에서 자주 일어나는 대용량 트래픽 & 데이터 처리 업무를 한번에 마스터할 수 있도록 모든 것을 담았습니다. 대기업 & 빅테크 현업 강사진 8인과 함께 하는 고퀄리티 현업 대비형 강의! 타사
fastcampus.co.kr
'MinimiProject > 아이돌 티켓팅 접속자 대기열 시스템' 카테고리의 다른 글
[대기열 시스템] 테스트를 위한 Embedded Redis (1) | 2025.02.17 |
---|---|
[대기열 시스템] Task Execution and Scheduling (1) | 2025.02.16 |
[대기열 시스템] Custom Exception (0) | 2025.02.13 |
[대기열 시스템] Spring WebFlux와 BlockHound (0) | 2025.02.11 |
[대기열 시스템] NullPointerException: Mocking (0) | 2025.02.10 |