1414import org .ezcode .codetest .domain .submission .exception .code .CodeReviewExceptionCode ;
1515import org .springframework .beans .factory .annotation .Value ;
1616import org .springframework .http .HttpHeaders ;
17+ import org .springframework .http .HttpStatusCode ;
1718import org .springframework .http .MediaType ;
1819import org .springframework .stereotype .Component ;
1920import org .springframework .transaction .interceptor .TransactionAspectSupport ;
3031@ RequiredArgsConstructor
3132public class OpenAIReviewClient implements ReviewClient {
3233
33- @ Value ("${OPEN_API_URL }" )
34+ @ Value ("${openai.api.url }" )
3435 private String openApiUrl ;
3536
36- @ Value ("${OPEN_API_KEY }" )
37+ @ Value ("${openai.api.key }" )
3738 private String openApiKey ;
3839 private WebClient webClient ;
3940 private final OpenAIMessageBuilder openAiMessageBuilder ;
@@ -77,7 +78,6 @@ public ReviewResult requestReview(ReviewPayload reviewPayload) {
7778 }
7879
7980 private String callChatApi (Map <String , Object > requestBody ) {
80-
8181 OpenAIResponse response = webClient .post ()
8282 .uri ("/v1/chat/completions" )
8383 .bodyValue (requestBody )
@@ -87,14 +87,29 @@ private String callChatApi(Map<String, Object> requestBody) {
8787 .retryWhen (
8888 Retry .backoff (3 , Duration .ofSeconds (1 ))
8989 .maxBackoff (Duration .ofSeconds (5 ))
90- .filter (ex -> ex instanceof WebClientResponseException
91- || ex instanceof TimeoutException )
90+ .filter (ex -> {
91+ if (ex instanceof TimeoutException ) {
92+ return true ;
93+ }
94+ if (ex instanceof WebClientResponseException ) {
95+ HttpStatusCode statusCode = ((WebClientResponseException ) ex ).getStatusCode ();
96+ // 5xx 서버 오류만 재시도 (502, 503 등)
97+ return statusCode .is5xxServerError ();
98+ }
99+ return false ;
100+ })
92101 .onRetryExhaustedThrow ((spec , signal ) -> signal .failure ())
93102 )
94- .onErrorMap (WebClientResponseException .class ,
95- ex -> new CodeReviewException (CodeReviewExceptionCode .REVIEW_SERVER_ERROR ))
96- .onErrorMap (TimeoutException .class ,
97- ex -> new CodeReviewException (CodeReviewExceptionCode .REVIEW_TIMEOUT ))
103+ .onErrorMap (WebClientResponseException .class , ex -> {
104+ HttpStatusCode statusCode = ex .getStatusCode ();
105+ String responseBody = ex .getResponseBodyAsString ();
106+ log .error ("OpenAI API 호출 실패 - Status: {}, Response Body: {}" , statusCode , responseBody , ex );
107+ return new CodeReviewException (CodeReviewExceptionCode .REVIEW_SERVER_ERROR );
108+ })
109+ .onErrorMap (TimeoutException .class , ex -> {
110+ log .error ("OpenAI API 호출 타임아웃" , ex );
111+ return new CodeReviewException (CodeReviewExceptionCode .REVIEW_TIMEOUT );
112+ })
98113 .block ();
99114
100115 return Objects .requireNonNull (response ).getReviewContent ();
0 commit comments