From 1ab78e881fec434adff8f1afd23b8fc9feef2f33 Mon Sep 17 00:00:00 2001 From: hyojin kim Date: Fri, 9 Jan 2026 13:39:18 +0900 Subject: [PATCH] :loud_sound: API Response Error Log Update --- .../reader/ComplianceDataRangeReader.java | 23 ++++++-- .../event/batch/reader/EventDataReader.java | 34 +++++++++++ .../reader/AnchorageCallsRangeReader.java | 19 +++++++ .../batch/reader/BerthCallsRangeReader.java | 19 +++++++ .../batch/reader/CurrentlyAtRangeReader.java | 19 +++++++ .../batch/reader/DestinationRangeReader.java | 19 +++++++ .../batch/reader/PortCallsRangeReader.java | 19 +++++++ .../batch/reader/StsOperationRangeReader.java | 24 ++++++-- .../reader/TerminalCallsRangeReader.java | 19 +++++++ .../batch/reader/TransitsRangeReader.java | 20 ++++++- .../batch/reader/PscApiReader.java | 22 +++++++- .../batch/reader/RiskDataRangeReader.java | 23 ++++++-- .../reader/ShipDetailUpdateDataReader.java | 56 +++++++++++-------- 13 files changed, 277 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/snp/batch/jobs/compliance/batch/reader/ComplianceDataRangeReader.java b/src/main/java/com/snp/batch/jobs/compliance/batch/reader/ComplianceDataRangeReader.java index 29754ac..81761f2 100644 --- a/src/main/java/com/snp/batch/jobs/compliance/batch/reader/ComplianceDataRangeReader.java +++ b/src/main/java/com/snp/batch/jobs/compliance/batch/reader/ComplianceDataRangeReader.java @@ -2,16 +2,14 @@ package com.snp.batch.jobs.compliance.batch.reader; import com.snp.batch.common.batch.reader.BaseApiReader; import com.snp.batch.jobs.compliance.batch.dto.ComplianceDto; -import com.snp.batch.jobs.shipdetail.batch.dto.ShipDetailComparisonData; import com.snp.batch.service.BatchDateService; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatusCode; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Map; @@ -115,6 +113,23 @@ public class ComplianceDataRangeReader extends BaseApiReader { .queryParam("toDate", params.get("toDate")) .build()) .retrieve() + // 1. 에러 상태 코드 감지 (4xx, 5xx) + .onStatus(HttpStatusCode::isError, clientResponse -> + clientResponse.bodyToMono(String.class) // 에러 바디를 문자열로 읽음 + .flatMap(errorBody -> { + // 2. 로그에 상태 코드와 에러 메세지 출력 + log.error("[{}] API 호출 오류 발생!", getReaderName()); + log.error("[{}] ERROR CODE: {}, REASON: {}", + getReaderName(), + clientResponse.statusCode(), + errorBody); + + // 3. 상위로 예외 던지기 (배치 중단을 원할 경우) + return Mono.error(new RuntimeException( + String.format("API 호출 실패 (%s): %s", clientResponse.statusCode(), errorBody) + )); + }) + ) .bodyToMono(new ParameterizedTypeReference>() {}) .block(); } diff --git a/src/main/java/com/snp/batch/jobs/event/batch/reader/EventDataReader.java b/src/main/java/com/snp/batch/jobs/event/batch/reader/EventDataReader.java index 78cc602..d0a657e 100644 --- a/src/main/java/com/snp/batch/jobs/event/batch/reader/EventDataReader.java +++ b/src/main/java/com/snp/batch/jobs/event/batch/reader/EventDataReader.java @@ -4,8 +4,10 @@ import com.snp.batch.common.batch.reader.BaseApiReader; import com.snp.batch.jobs.event.batch.dto.*; import com.snp.batch.service.BatchDateService; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatusCode; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; import java.time.LocalDateTime; import java.util.*; @@ -210,6 +212,22 @@ public class EventDataReader extends BaseApiReader { .queryParam("toDay", params.get("toDay")) .build()) .retrieve() + .onStatus(HttpStatusCode::isError, clientResponse -> + clientResponse.bodyToMono(String.class) // 에러 바디를 문자열로 읽음 + .flatMap(errorBody -> { + // 2. 로그에 상태 코드와 에러 메세지 출력 + log.error("[{}] API 호출 오류 발생!", getReaderName()); + log.error("[{}] ERROR CODE: {}, REASON: {}", + getReaderName(), + clientResponse.statusCode(), + errorBody); + + // 3. 상위로 예외 던지기 (배치 중단을 원할 경우) + return Mono.error(new RuntimeException( + String.format("API 호출 실패 (%s): %s", clientResponse.statusCode(), errorBody) + )); + }) + ) .bodyToMono(EventResponse.class) .block(); } @@ -222,6 +240,22 @@ public class EventDataReader extends BaseApiReader { .queryParam("eventID", eventId) .build()) .retrieve() + .onStatus(HttpStatusCode::isError, clientResponse -> + clientResponse.bodyToMono(String.class) // 에러 바디를 문자열로 읽음 + .flatMap(errorBody -> { + // 2. 로그에 상태 코드와 에러 메세지 출력 + log.error("[{}] API 호출 오류 발생!", getReaderName()); + log.error("[{}] ERROR CODE: {}, REASON: {}", + getReaderName(), + clientResponse.statusCode(), + errorBody); + + // 3. 상위로 예외 던지기 (배치 중단을 원할 경우) + return Mono.error(new RuntimeException( + String.format("API 호출 실패 (%s): %s", clientResponse.statusCode(), errorBody) + )); + }) + ) .bodyToMono(EventDetailResponse.class) .block(); } diff --git a/src/main/java/com/snp/batch/jobs/movement/batch/reader/AnchorageCallsRangeReader.java b/src/main/java/com/snp/batch/jobs/movement/batch/reader/AnchorageCallsRangeReader.java index 167e98c..90fefe9 100644 --- a/src/main/java/com/snp/batch/jobs/movement/batch/reader/AnchorageCallsRangeReader.java +++ b/src/main/java/com/snp/batch/jobs/movement/batch/reader/AnchorageCallsRangeReader.java @@ -6,6 +6,8 @@ import com.snp.batch.service.BatchDateService; import lombok.extern.slf4j.Slf4j; import org.springframework.batch.core.configuration.annotation.StepScope; import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.http.HttpStatusCode; +import reactor.core.publisher.Mono; import java.util.List; import java.util.Map; @@ -102,6 +104,23 @@ public class AnchorageCallsRangeReader extends BaseApiReader .queryParam("stopDate", params.get("toDate")) .build()) .retrieve() + // 1. 에러 상태 코드 감지 (4xx, 5xx) + .onStatus(HttpStatusCode::isError, clientResponse -> + clientResponse.bodyToMono(String.class) // 에러 바디를 문자열로 읽음 + .flatMap(errorBody -> { + // 2. 로그에 상태 코드와 에러 메세지 출력 + log.error("[{}] API 호출 오류 발생!", getReaderName()); + log.error("[{}] ERROR CODE: {}, REASON: {}", + getReaderName(), + clientResponse.statusCode(), + errorBody); + + // 3. 상위로 예외 던지기 (배치 중단을 원할 경우) + return Mono.error(new RuntimeException( + String.format("API 호출 실패 (%s): %s", clientResponse.statusCode(), errorBody) + )); + }) + ) .bodyToFlux(AnchorageCallsDto.class) .collectList() .block(); diff --git a/src/main/java/com/snp/batch/jobs/movement/batch/reader/BerthCallsRangeReader.java b/src/main/java/com/snp/batch/jobs/movement/batch/reader/BerthCallsRangeReader.java index 539f79a..85d7b82 100644 --- a/src/main/java/com/snp/batch/jobs/movement/batch/reader/BerthCallsRangeReader.java +++ b/src/main/java/com/snp/batch/jobs/movement/batch/reader/BerthCallsRangeReader.java @@ -6,6 +6,8 @@ import com.snp.batch.service.BatchDateService; import lombok.extern.slf4j.Slf4j; import org.springframework.batch.core.configuration.annotation.StepScope; import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.http.HttpStatusCode; +import reactor.core.publisher.Mono; import java.util.List; import java.util.Map; @@ -101,6 +103,23 @@ public class BerthCallsRangeReader extends BaseApiReader { .queryParam("stopDate", params.get("toDate")) .build()) .retrieve() + // 1. 에러 상태 코드 감지 (4xx, 5xx) + .onStatus(HttpStatusCode::isError, clientResponse -> + clientResponse.bodyToMono(String.class) // 에러 바디를 문자열로 읽음 + .flatMap(errorBody -> { + // 2. 로그에 상태 코드와 에러 메세지 출력 + log.error("[{}] API 호출 오류 발생!", getReaderName()); + log.error("[{}] ERROR CODE: {}, REASON: {}", + getReaderName(), + clientResponse.statusCode(), + errorBody); + + // 3. 상위로 예외 던지기 (배치 중단을 원할 경우) + return Mono.error(new RuntimeException( + String.format("API 호출 실패 (%s): %s", clientResponse.statusCode(), errorBody) + )); + }) + ) .bodyToFlux(BerthCallsDto.class) .collectList() .block(); diff --git a/src/main/java/com/snp/batch/jobs/movement/batch/reader/CurrentlyAtRangeReader.java b/src/main/java/com/snp/batch/jobs/movement/batch/reader/CurrentlyAtRangeReader.java index 4f72777..00cbf33 100644 --- a/src/main/java/com/snp/batch/jobs/movement/batch/reader/CurrentlyAtRangeReader.java +++ b/src/main/java/com/snp/batch/jobs/movement/batch/reader/CurrentlyAtRangeReader.java @@ -6,6 +6,8 @@ import com.snp.batch.service.BatchDateService; import lombok.extern.slf4j.Slf4j; import org.springframework.batch.core.configuration.annotation.StepScope; import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.http.HttpStatusCode; +import reactor.core.publisher.Mono; import java.util.List; import java.util.Map; @@ -100,6 +102,23 @@ public class CurrentlyAtRangeReader extends BaseApiReader { .queryParam("stopDate", params.get("toDate")) .build()) .retrieve() + // 1. 에러 상태 코드 감지 (4xx, 5xx) + .onStatus(HttpStatusCode::isError, clientResponse -> + clientResponse.bodyToMono(String.class) // 에러 바디를 문자열로 읽음 + .flatMap(errorBody -> { + // 2. 로그에 상태 코드와 에러 메세지 출력 + log.error("[{}] API 호출 오류 발생!", getReaderName()); + log.error("[{}] ERROR CODE: {}, REASON: {}", + getReaderName(), + clientResponse.statusCode(), + errorBody); + + // 3. 상위로 예외 던지기 (배치 중단을 원할 경우) + return Mono.error(new RuntimeException( + String.format("API 호출 실패 (%s): %s", clientResponse.statusCode(), errorBody) + )); + }) + ) .bodyToFlux(CurrentlyAtDto.class) .collectList() .block(); diff --git a/src/main/java/com/snp/batch/jobs/movement/batch/reader/DestinationRangeReader.java b/src/main/java/com/snp/batch/jobs/movement/batch/reader/DestinationRangeReader.java index d6a9b39..af41064 100644 --- a/src/main/java/com/snp/batch/jobs/movement/batch/reader/DestinationRangeReader.java +++ b/src/main/java/com/snp/batch/jobs/movement/batch/reader/DestinationRangeReader.java @@ -6,6 +6,8 @@ import com.snp.batch.service.BatchDateService; import lombok.extern.slf4j.Slf4j; import org.springframework.batch.core.configuration.annotation.StepScope; import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.http.HttpStatusCode; +import reactor.core.publisher.Mono; import java.util.List; import java.util.Map; @@ -98,6 +100,23 @@ public class DestinationRangeReader extends BaseApiReader { .queryParam("stopDate", params.get("toDate")) .build()) .retrieve() + // 1. 에러 상태 코드 감지 (4xx, 5xx) + .onStatus(HttpStatusCode::isError, clientResponse -> + clientResponse.bodyToMono(String.class) // 에러 바디를 문자열로 읽음 + .flatMap(errorBody -> { + // 2. 로그에 상태 코드와 에러 메세지 출력 + log.error("[{}] API 호출 오류 발생!", getReaderName()); + log.error("[{}] ERROR CODE: {}, REASON: {}", + getReaderName(), + clientResponse.statusCode(), + errorBody); + + // 3. 상위로 예외 던지기 (배치 중단을 원할 경우) + return Mono.error(new RuntimeException( + String.format("API 호출 실패 (%s): %s", clientResponse.statusCode(), errorBody) + )); + }) + ) .bodyToFlux(DestinationDto.class) .collectList() .block(); diff --git a/src/main/java/com/snp/batch/jobs/movement/batch/reader/PortCallsRangeReader.java b/src/main/java/com/snp/batch/jobs/movement/batch/reader/PortCallsRangeReader.java index 51ec562..a8dc9c1 100644 --- a/src/main/java/com/snp/batch/jobs/movement/batch/reader/PortCallsRangeReader.java +++ b/src/main/java/com/snp/batch/jobs/movement/batch/reader/PortCallsRangeReader.java @@ -6,6 +6,8 @@ import com.snp.batch.service.BatchDateService; import lombok.extern.slf4j.Slf4j; import org.springframework.batch.core.configuration.annotation.StepScope; import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.http.HttpStatusCode; +import reactor.core.publisher.Mono; import java.util.List; import java.util.Map; @@ -100,6 +102,23 @@ public class PortCallsRangeReader extends BaseApiReader { .queryParam("stopDate", params.get("toDate")) .build()) .retrieve() + // 1. 에러 상태 코드 감지 (4xx, 5xx) + .onStatus(HttpStatusCode::isError, clientResponse -> + clientResponse.bodyToMono(String.class) // 에러 바디를 문자열로 읽음 + .flatMap(errorBody -> { + // 2. 로그에 상태 코드와 에러 메세지 출력 + log.error("[{}] API 호출 오류 발생!", getReaderName()); + log.error("[{}] ERROR CODE: {}, REASON: {}", + getReaderName(), + clientResponse.statusCode(), + errorBody); + + // 3. 상위로 예외 던지기 (배치 중단을 원할 경우) + return Mono.error(new RuntimeException( + String.format("API 호출 실패 (%s): %s", clientResponse.statusCode(), errorBody) + )); + }) + ) .bodyToFlux(PortCallsDto.class) .collectList() .block(); diff --git a/src/main/java/com/snp/batch/jobs/movement/batch/reader/StsOperationRangeReader.java b/src/main/java/com/snp/batch/jobs/movement/batch/reader/StsOperationRangeReader.java index 9977edc..b2f6cec 100644 --- a/src/main/java/com/snp/batch/jobs/movement/batch/reader/StsOperationRangeReader.java +++ b/src/main/java/com/snp/batch/jobs/movement/batch/reader/StsOperationRangeReader.java @@ -5,11 +5,10 @@ import com.snp.batch.jobs.movement.batch.dto.StsOperationDto; import com.snp.batch.service.BatchDateService; import lombok.extern.slf4j.Slf4j; import org.springframework.batch.core.configuration.annotation.StepScope; -import org.springframework.beans.factory.annotation.Value; import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.http.HttpStatusCode; +import reactor.core.publisher.Mono; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Map; @@ -103,6 +102,23 @@ public class StsOperationRangeReader extends BaseApiReader { .queryParam("stopDate", params.get("toDate")) .build()) .retrieve() + // 1. 에러 상태 코드 감지 (4xx, 5xx) + .onStatus(HttpStatusCode::isError, clientResponse -> + clientResponse.bodyToMono(String.class) // 에러 바디를 문자열로 읽음 + .flatMap(errorBody -> { + // 2. 로그에 상태 코드와 에러 메세지 출력 + log.error("[{}] API 호출 오류 발생!", getReaderName()); + log.error("[{}] ERROR CODE: {}, REASON: {}", + getReaderName(), + clientResponse.statusCode(), + errorBody); + + // 3. 상위로 예외 던지기 (배치 중단을 원할 경우) + return Mono.error(new RuntimeException( + String.format("API 호출 실패 (%s): %s", clientResponse.statusCode(), errorBody) + )); + }) + ) .bodyToFlux(StsOperationDto.class) .collectList() .block(); @@ -113,8 +129,6 @@ public class StsOperationRangeReader extends BaseApiReader { if (data == null) { int totalBatches = (int) Math.ceil((double) allData.size() / batchSize); log.info("[{}] 전체 {} 개 배치 처리 완료", getReaderName(), totalBatches); - /*log.info("[{}] 총 {} 개의 IMO 번호에 대한 API 호출 종료", - getReaderName(), allImoNumbers.size());*/ } } diff --git a/src/main/java/com/snp/batch/jobs/movement/batch/reader/TerminalCallsRangeReader.java b/src/main/java/com/snp/batch/jobs/movement/batch/reader/TerminalCallsRangeReader.java index 2213167..abf9f3c 100644 --- a/src/main/java/com/snp/batch/jobs/movement/batch/reader/TerminalCallsRangeReader.java +++ b/src/main/java/com/snp/batch/jobs/movement/batch/reader/TerminalCallsRangeReader.java @@ -6,6 +6,8 @@ import com.snp.batch.service.BatchDateService; import lombok.extern.slf4j.Slf4j; import org.springframework.batch.core.configuration.annotation.StepScope; import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.http.HttpStatusCode; +import reactor.core.publisher.Mono; import java.util.List; import java.util.Map; @@ -99,6 +101,23 @@ public class TerminalCallsRangeReader extends BaseApiReader { .queryParam("stopDate", params.get("toDate")) .build()) .retrieve() + // 1. 에러 상태 코드 감지 (4xx, 5xx) + .onStatus(HttpStatusCode::isError, clientResponse -> + clientResponse.bodyToMono(String.class) // 에러 바디를 문자열로 읽음 + .flatMap(errorBody -> { + // 2. 로그에 상태 코드와 에러 메세지 출력 + log.error("[{}] API 호출 오류 발생!", getReaderName()); + log.error("[{}] ERROR CODE: {}, REASON: {}", + getReaderName(), + clientResponse.statusCode(), + errorBody); + + // 3. 상위로 예외 던지기 (배치 중단을 원할 경우) + return Mono.error(new RuntimeException( + String.format("API 호출 실패 (%s): %s", clientResponse.statusCode(), errorBody) + )); + }) + ) .bodyToFlux(TerminalCallsDto.class) .collectList() .block(); diff --git a/src/main/java/com/snp/batch/jobs/movement/batch/reader/TransitsRangeReader.java b/src/main/java/com/snp/batch/jobs/movement/batch/reader/TransitsRangeReader.java index f62c3df..f460574 100644 --- a/src/main/java/com/snp/batch/jobs/movement/batch/reader/TransitsRangeReader.java +++ b/src/main/java/com/snp/batch/jobs/movement/batch/reader/TransitsRangeReader.java @@ -6,6 +6,8 @@ import com.snp.batch.service.BatchDateService; import lombok.extern.slf4j.Slf4j; import org.springframework.batch.core.configuration.annotation.StepScope; import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.http.HttpStatusCode; +import reactor.core.publisher.Mono; import java.util.List; import java.util.Map; @@ -86,7 +88,6 @@ public class TransitsRangeReader extends BaseApiReader { /** * Query Parameter를 사용한 API 호출 - * @param startDate,stopDate * @return API 응답 */ private List callApiWithBatch() { @@ -100,6 +101,23 @@ public class TransitsRangeReader extends BaseApiReader { .queryParam("stopDate", params.get("toDate")) .build()) .retrieve() + // 1. 에러 상태 코드 감지 (4xx, 5xx) + .onStatus(HttpStatusCode::isError, clientResponse -> + clientResponse.bodyToMono(String.class) // 에러 바디를 문자열로 읽음 + .flatMap(errorBody -> { + // 2. 로그에 상태 코드와 에러 메세지 출력 + log.error("[{}] API 호출 오류 발생!", getReaderName()); + log.error("[{}] ERROR CODE: {}, REASON: {}", + getReaderName(), + clientResponse.statusCode(), + errorBody); + + // 3. 상위로 예외 던지기 (배치 중단을 원할 경우) + return Mono.error(new RuntimeException( + String.format("API 호출 실패 (%s): %s", clientResponse.statusCode(), errorBody) + )); + }) + ) .bodyToFlux(TransitsDto.class) .collectList() .block(); diff --git a/src/main/java/com/snp/batch/jobs/pscInspection/batch/reader/PscApiReader.java b/src/main/java/com/snp/batch/jobs/pscInspection/batch/reader/PscApiReader.java index 4883e09..b97a65d 100644 --- a/src/main/java/com/snp/batch/jobs/pscInspection/batch/reader/PscApiReader.java +++ b/src/main/java/com/snp/batch/jobs/pscInspection/batch/reader/PscApiReader.java @@ -7,15 +7,14 @@ import com.snp.batch.jobs.pscInspection.batch.dto.PscInspectionDto; import com.snp.batch.service.BatchDateService; import lombok.extern.slf4j.Slf4j; import org.springframework.batch.core.configuration.annotation.StepScope; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatusCode; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.OffsetDateTime; -import java.time.format.DateTimeFormatter; import java.util.Collections; import java.util.List; import java.util.Map; @@ -117,6 +116,23 @@ public class PscApiReader extends BaseApiReader { .queryParam("toDay", params.get("toDay")) .build()) .retrieve() + // 1. 에러 상태 코드 감지 (4xx, 5xx) + .onStatus(HttpStatusCode::isError, clientResponse -> + clientResponse.bodyToMono(String.class) // 에러 바디를 문자열로 읽음 + .flatMap(errorBody -> { + // 2. 로그에 상태 코드와 에러 메세지 출력 + log.error("[{}] API 호출 오류 발생!", getReaderName()); + log.error("[{}] ERROR CODE: {}, REASON: {}", + getReaderName(), + clientResponse.statusCode(), + errorBody); + + // 3. 상위로 예외 던지기 (배치 중단을 원할 경우) + return Mono.error(new RuntimeException( + String.format("API 호출 실패 (%s): %s", clientResponse.statusCode(), errorBody) + )); + }) + ) .bodyToMono(String.class) .block(); diff --git a/src/main/java/com/snp/batch/jobs/risk/batch/reader/RiskDataRangeReader.java b/src/main/java/com/snp/batch/jobs/risk/batch/reader/RiskDataRangeReader.java index fc1be7a..5e4bed8 100644 --- a/src/main/java/com/snp/batch/jobs/risk/batch/reader/RiskDataRangeReader.java +++ b/src/main/java/com/snp/batch/jobs/risk/batch/reader/RiskDataRangeReader.java @@ -1,17 +1,15 @@ package com.snp.batch.jobs.risk.batch.reader; import com.snp.batch.common.batch.reader.BaseApiReader; -import com.snp.batch.jobs.compliance.batch.dto.ComplianceDto; import com.snp.batch.jobs.risk.batch.dto.RiskDto; import com.snp.batch.service.BatchDateService; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatusCode; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Map; @@ -112,6 +110,23 @@ public class RiskDataRangeReader extends BaseApiReader { .queryParam("toDate", params.get("toDate")) .build()) .retrieve() + // 1. 에러 상태 코드 감지 (4xx, 5xx) + .onStatus(HttpStatusCode::isError, clientResponse -> + clientResponse.bodyToMono(String.class) // 에러 바디를 문자열로 읽음 + .flatMap(errorBody -> { + // 2. 로그에 상태 코드와 에러 메세지 출력 + log.error("[{}] API 호출 오류 발생!", getReaderName()); + log.error("[{}] ERROR CODE: {}, REASON: {}", + getReaderName(), + clientResponse.statusCode(), + errorBody); + + // 3. 상위로 예외 던지기 (배치 중단을 원할 경우) + return Mono.error(new RuntimeException( + String.format("API 호출 실패 (%s): %s", clientResponse.statusCode(), errorBody) + )); + }) + ) .bodyToMono(new ParameterizedTypeReference>() {}) .block(); } diff --git a/src/main/java/com/snp/batch/jobs/shipdetail/batch/reader/ShipDetailUpdateDataReader.java b/src/main/java/com/snp/batch/jobs/shipdetail/batch/reader/ShipDetailUpdateDataReader.java index 53f5458..d021ac5 100644 --- a/src/main/java/com/snp/batch/jobs/shipdetail/batch/reader/ShipDetailUpdateDataReader.java +++ b/src/main/java/com/snp/batch/jobs/shipdetail/batch/reader/ShipDetailUpdateDataReader.java @@ -9,32 +9,12 @@ import com.snp.batch.service.BatchDateService; import lombok.extern.slf4j.Slf4j; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.http.HttpStatusCode; +import reactor.core.publisher.Mono; -import java.time.LocalDate; -import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; -/** - * 선박 상세 정보 Reader (v2.0 - Chunk 기반) - * - * 기능: - * 1. ship_data 테이블에서 IMO 번호 전체 조회 (최초 1회) - * 2. IMO 번호를 100개씩 분할하여 배치 단위로 처리 - * 3. fetchNextBatch() 호출 시마다 100개씩 API 호출 - * 4. Spring Batch가 100건씩 Process → Write 수행 - * - * Chunk 처리 흐름: - * - beforeFetch() → IMO 전체 조회 (1회) - * - fetchNextBatch() → 100개 IMO로 API 호출 (1,718회) - * - read() → 1건씩 반환 (100번) - * - Processor/Writer → 100건 처리 - * - 반복... (1,718번의 Chunk) - * - * 기존 방식과의 차이: - * - 기존: 17만건 전체 메모리 로드 → Process → Write - * - 신규: 100건씩 로드 → Process → Write (Chunk 1,718회) - */ @Slf4j public class ShipDetailUpdateDataReader extends BaseApiReader { @@ -247,6 +227,22 @@ public class ShipDetailUpdateDataReader extends BaseApiReader + clientResponse.bodyToMono(String.class) // 에러 바디를 문자열로 읽음 + .flatMap(errorBody -> { + // 2. 로그에 상태 코드와 에러 메세지 출력 + log.error("[{}] API 호출 오류 발생!", getReaderName()); + log.error("[{}] ERROR CODE: {}, REASON: {}", + getReaderName(), + clientResponse.statusCode(), + errorBody); + + // 3. 상위로 예외 던지기 (배치 중단을 원할 경우) + return Mono.error(new RuntimeException( + String.format("API 호출 실패 (%s): %s", clientResponse.statusCode(), errorBody) + )); + }) + ) .bodyToMono(ShipDetailApiResponse.class) .block(); } @@ -275,6 +271,22 @@ public class ShipDetailUpdateDataReader extends BaseApiReader + clientResponse.bodyToMono(String.class) // 에러 바디를 문자열로 읽음 + .flatMap(errorBody -> { + // 2. 로그에 상태 코드와 에러 메세지 출력 + log.error("[{}] API 호출 오류 발생!", getReaderName()); + log.error("[{}] ERROR CODE: {}, REASON: {}", + getReaderName(), + clientResponse.statusCode(), + errorBody); + + // 3. 상위로 예외 던지기 (배치 중단을 원할 경우) + return Mono.error(new RuntimeException( + String.format("API 호출 실패 (%s): %s", clientResponse.statusCode(), errorBody) + )); + }) + ) .bodyToMono(ShipUpdateApiResponse.class) .block(); }