client 호출 용량 상향 조정. chunk 방식 추가했지만 사용은 아직 안함.

This commit is contained in:
Hyojin Ahn 2026-06-11 16:10:08 -04:00
parent e8eb4381f2
commit 3ed7f0c7f1
1 changed files with 81 additions and 21 deletions

View File

@ -2,37 +2,105 @@ package com.goi.erp.client;
import com.goi.erp.dto.ScheduleWorkerRequestDto;
import com.goi.erp.dto.ext.ExtSamsaraOdometerFetchCommand;
import com.goi.erp.dto.ext.ExtSamsaraOdometerRecordDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Service
public class SamsaraStatOdometerClient {
/** WebClient in-memory 버퍼 한계 (기본 256KB → 16MB로 상향) */
private static final int MAX_IN_MEMORY_SIZE = 16 * 1024 * 1024; // 16MB
private final WebClient webClient;
/** 한 번 호출 시 보낼 externalId 최대 개수 (기본 100) */
private final int chunkSize;
public SamsaraStatOdometerClient(
WebClient.Builder webClientBuilder,
@Value("${integration.api.base-url}") String integrationBaseUrl
@Value("${integration.api.base-url}") String integrationBaseUrl,
@Value("${integration.api.odometer.chunk-size:100}") int chunkSize
) {
this.webClient = webClientBuilder
.baseUrl(integrationBaseUrl)
// DataBufferLimitException(262144) 방지
.codecs(configurer ->
configurer.defaultCodecs().maxInMemorySize(MAX_IN_MEMORY_SIZE))
.build();
this.chunkSize = chunkSize;
}
/**
* integration-service 호출
* POST /vehicle/odometer/fetch
* POST /vehicle/stat/odometer/fetch
*
* externalIds chunkSize 넘으면 나눠서 호출하고 records 병합한다.
*/
public ExtSamsaraOdometerFetchCommand fetchOdometer(
ScheduleWorkerRequestDto request
) {
List<String> externalIds = request.getVehicleExternalIds();
// externalIds 없거나 chunkSize 이하이면 단건 호출
if (externalIds == null || externalIds.size() <= chunkSize) {
return callOnce(request);
}
// chunk 단위로 나눠서 호출 records 병합
final List<String> originalIds = externalIds;
List<ExtSamsaraOdometerRecordDto> mergedRecords = new ArrayList<>();
String source = null;
LocalDateTime fetchedAt = null;
try {
for (int i = 0; i < originalIds.size(); i += chunkSize) {
List<String> chunk = originalIds.subList(
i, Math.min(i + chunkSize, originalIds.size()));
// 호출자 객체에 청크 세팅 (마지막에 원복)
request.setVehicleExternalIds(chunk);
ExtSamsaraOdometerFetchCommand part = callOnce(request);
if (part == null || part.getRecords() == null) {
continue;
}
// source / fetchedAt 응답 기준으로 유지
if (source == null) {
source = part.getSource();
fetchedAt = part.getFetchedAt();
}
mergedRecords.addAll(part.getRecords());
}
} finally {
// 호출자 request 객체 원복 (부수효과 방지)
request.setVehicleExternalIds(originalIds);
}
log.info("[ODOMETER_RAW][CHUNK] totalExternalIds={} chunkSize={} mergedRecords={}",
originalIds.size(), chunkSize, mergedRecords.size());
return ExtSamsaraOdometerFetchCommand.builder()
.source(source)
.fetchedAt(fetchedAt)
.records(mergedRecords)
.build();
}
/**
* 실제 단건 호출. 현재 request 세팅된 externalIds 그대로 호출한다.
*/
private ExtSamsaraOdometerFetchCommand callOnce(
ScheduleWorkerRequestDto request
) {
return webClient.post()
.uri("/vehicle/stat/odometer/fetch")
.bodyValue(request)
@ -41,18 +109,10 @@ public class SamsaraStatOdometerClient {
status -> status.is4xxClientError() || status.is5xxServerError(),
resp -> resp.bodyToMono(String.class)
.map(body ->
new RuntimeException(
"INTEGRATION_ERROR: " + body
)
new RuntimeException("INTEGRATION_ERROR: " + body)
)
)
.bodyToMono(ExtSamsaraOdometerFetchCommand.class)
.block();
} catch (Exception e) {
// 메시지가 OPR 서비스 레벨까지 올라감
throw e;
}
}
}