Repository navigation
Conversation
입력 오류와 권한 거부가 500 으로 나갔다. CareServiceException 은 상태 코드를 문자열로 들고 다니고, 전역 핸들러가 그 문자열을 보고 상태를 정한다. 매핑은 네 가지(UNAUTHORIZED, FORBIDDEN, USER_NOT_FOUND, KAKAO*)뿐이고 나머지는 전부 INTERNAL_SERVER_ERROR 다. throw 47곳 중 39곳이 코드를 주지 않으므로 그대로 500 이 된다. 두 갈래로 나타났다. 1. 정상적인 거절이 장애로 보고된다 예약 8곳이 그랬다. 이미 취소한 예약을 또 취소(409), 완료된 예약 수정(409), 끝나는 시각이 시작보다 앞(400), 과거 시간(400), 자리 없음(409) 이 전부 500 이었다. 마지막이 특히 나쁘다 - 정원이 찬 인기 시설일수록 500 이 더 쌓여 정상 동작이 장애 지표를 오염시킨다. 상태가 맞지 않아 거절하는 경우를 위해 BOOKING_STATE_CONFLICT(F005, 409)를 더했다. 요청 자체는 멀쩡하고 대상의 상태가 맞지 않은 것이라 400 이 아니다. 2. catch (Exception e) 가 안쪽의 403·404 를 삼킨다 알림 상세 조회는 소유권 검사가 403 을 던지는데 같은 try 를 감싼 catch 가 받아 500 으로 바꿨다. 클라이언트는 "권한이 없다" 와 "서버가 고장났다" 를 구분할 수 없고, 로그에는 서버 오류로 쌓여 권한 탐색 시도가 장애로 보인다. 요청 경로의 24곳에 도메인 예외를 먼저 다시 던지는 절을 넣었다. 삼키던 IllegalArgumentException 중 "찾을 수 없습니다" 는 ResourceNotFoundException 으로 바꿔 404 가 되게 했다. 건드리지 않은 것: - 백그라운드 동기화(external/publicdata)는 감싸는 것이 맞다. HTTP 응답이 없다. - EmailVerificationService 의 발송 실패 catch 는 쿨다운 키를 지운다. 재던지기를 넣으면 그 정리를 건너뛰어 사용자가 1분간 재시도조차 못 한다. - LegalDocumentService 는 클래스패스 파일만 읽어 도메인 예외가 나올 수 없다. 넣어 봐야 죽은 코드다. 먼저 실패 테스트로 현재 상태를 드러냈다 - 알림 403/404 두 개, 예약 409/400 다섯 개. 일곱 개 모두 500 쪽으로 실패하는 것을 확인한 뒤 고쳤다. 기존 CareFacilityBookingServiceTest 세 개가 깨졌고 그게 맞다. 그 테스트가 고정하던 것이 바로 이 버그였다 - 거부한다는 사실은 맞게 봤지만 거부가 500 으로 나간다는 것까지 같이 굳혀 두고 있었다. 타입만 바꾸지 않고 상태 코드까지 단언하도록 올렸다. 클래스가 아니라 계약을 지켜야 다시 돌아가지 않는다.
This was referenced Oct 24, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #158
무엇이 문제였나
입력 오류와 권한 거부가 500 Internal Server Error 로 나갔다.
CareServiceException은 상태 코드를 문자열로 들고 다니고, 전역 핸들러가 그 문자열을 보고상태를 정한다. 그런데 매핑이 네 가지뿐이다.
세어 보니
throw new CareServiceException(...)47곳 중 39곳이 코드를 주지 않는다. 코드 없이던지면
CARE_SERVICE_ERROR가 되고, 매핑에 없으므로 500 이다.두 갈래로 나타났다
1. 정상적인 거절이 장애로 보고된다
마지막 줄이 특히 나쁘다. 정원이 찬 인기 시설일수록 500 이 더 쌓인다 — 정상 동작이 장애
지표를 오염시킨다. 사용자가 두 번 눌렀을 뿐인데 운영에는 서버 장애로 보인다.
상태가 맞지 않아 거절하는 경우를 위해
BOOKING_STATE_CONFLICT(F005, 409)를 더했다. 요청 자체는멀쩡하고 대상의 상태가 맞지 않은 것이라 400 이 아니다.
2.
catch (Exception e)가 안쪽의 403·404 를 삼킨다소유권 검사가 403 을 던지는데 500 으로 나갔다. 클라이언트는 "권한이 없다" 와 "서버가
고장났다" 를 구분할 수 없고, 로그에는 서버 오류로 쌓여 권한 탐색 시도가 장애로 보인다.
CareCodeException이BusinessException·ResourceNotFoundException·UserNotFoundException의공통 조상이라, 요청 경로 24곳에 한 줄짜리 절을 앞세웠다.
삼키던
IllegalArgumentException중 "찾을 수 없습니다" 는ResourceNotFoundException으로 바꿔404 가 되게 했다.
건드리지 않은 곳 — 그리고 그 이유
external/publicdata)는 감싸는 것이 맞다. HTTP 응답이 없으니 상태 코드가의미 없고, 한 건이 실패해도 동기화 전체는 이어져야 한다.
EmailVerificationService의 발송 실패 catch 는 쿨다운 키를 지운다. 재던지기를 앞세우면그 정리를 건너뛰어 발송이 실패했는데 사용자가 1분간 재시도조차 못 하게 된다. 처음엔
기계적으로 넣었다가 되돌렸다.
LegalDocumentService는 클래스패스 파일만 읽어 도메인 예외가 나올 수 없다. 넣어 봐야죽은 코드다.
테스트
먼저 실패시켰다. 7개 모두 500 쪽으로 실패하는 것을 확인한 뒤 고쳤다.
실패 당시 메시지:
기존 테스트 3개가 깨졌고, 그게 맞다
CareFacilityBookingServiceTest의 세 개가CareServiceException을 기대하고 있었다. 그 테스트가고정하던 것이 바로 이 버그였다 — 거부한다는 사실은 맞게 봤지만, 거부가 500 으로 나간다는 것까지
같이 굳혀 두고 있었다.
타입만
BusinessException으로 바꾸지 않고 상태 코드까지 단언하도록 올렸다. 클래스가 아니라계약을 지켜야 다음에 또 500 으로 돌아가지 않는다.
좋아지지 않은 것
CareServiceException은 그대로 남아 있다. 이 PR 은 상태 코드가 틀린 곳만 고쳤고, 두 예외체계를 하나로 합치지 않았다([ 아키텍처 ] 같은 일을 여러 방식으로 해서 구조가 지저분하다 #132 2단계). 남은
CareServiceException은 여전히 문자열 코드로상태를 정하고, 코드를 주지 않으면 500 이다 — 같은 함정이 남아 있다.
조용히 달라지고, 그걸 기대하는 계약 테스트가 있다.
catch (Exception e)는 원인을 덮어쓰는 문제가 그대로다. HTTP 와 무관해이 PR 범위에서 뺐지만, 실패 원인이 로그에만 남고 동기화 상태에는 안 드러난다.