본문 바로가기

💻Spring

WebClient를 활용한 병렬 API 호출 및 예외 처리

반응형

서론

과제 테스트를 하며 외부 서버와의 통신으로 데이터를 받아와야했는데, 호출 시간을 단축 시켜야하는 요구사항이 있었다.

데이터를 분할하여 여러 요청들을 다른 서버로 요청하여 데이터를 받아오는 로직이였고, 

실패 응답시 재호출에는 약 10초간 지연시간이 있었기 때문에 재호출 로직을 고려하여

병렬로 호출을 해야겠다고 생각을 하여 WebClient를 이용한 병렬 API 통신을 진행하였다.

 

본론

데이터를 분할하여 서버로 병렬 요청을 하는 로직이였기 때문에 로직은 다음과 같았다.

1. entity에 서버로 요청할 횟수만큼 requestCount를 설정하고 저장한다.

2. 반복문을 통해 데이터를 분할하여 RequestDto를 생성한다.

3. 생성한 RequestDto로 WebClient를 생성하여 Mono 객체를 생성한다.

     - 각 Mono에는 에러 발생에 대한 처리를 한다.

4. 반복문을 통해 생성된 각 Mono를 List에 담아 Flux로 변경하여 subscribe를 통해 병렬로 요청을 한다.

 

특히 이 중 Mono의 예외 (500 에러) 발생 시, 10초의 지연시간을 갖고 약 3회 재호출을 진행하고

3회째 시도했을때에도 에러가 발생했을 경우 요청 횟수를 감소시키는 로직이 필요했기 때문에

Mono와 Mono를 합친 Flux의 subscribe 각각 예외 처리가 필요했다.

 

먼저 Mono쪽 코드를 보면

entity.addRequestCount(count);
List<Mono<String>> monos = new ArrayList<>();
int start = 0;
int end = n;
for (int i = 0; i < count; i++) {
    RequestDto requestDto = new RequestDto(start += n, end += n);

    // 병렬로 AI API 요청, 5xx 에러시 10초 대기 후 재요청 (최대 3회)
    Mono<String> mono = webClient.post()
            .uri(END_POINT)
            .contentType(MediaType.APPLICATION_JSON)
            .bodyValue(requestDto)
            .retrieve()
            .bodyToMono(String.class)
            // 10초 지연 후 최대 3회 재요청
            .retryWhen(Retry.fixedDelay(3, Duration.ofSeconds(10)));
    monos.add(mono);
}

 

retryWhen 메서드를 통해 10초의 지연시간을 통해 3회를 추가 요청을 했다.

 

AtomicInteger failCount = new AtomicInteger();
Flux.merge(monos)
        .then()
        .onErrorContinue((error, element) -> {
            failCount.getAndIncrement();
            log.error("err : {}, element : {} ", error.getMessage(), element);
        })
        .doFinally(result -> {
            entity.subRequestCount(failCount.get());
            entityRepository.save(entity);
        })
        .subscribe();
      
entityRepository.save(entity);

 

이후 해당 Mono들의 개별적인 예외처리를 위해 

onErrorContinue 메서드를 통해 예외 발생시 failCount를 증가시키고, 다른 요청들은 정상적으로 진행시켰다.

이후 doFinally 메서드를 통해 모든 스트림이 끝난 후 최종적으로 실패한 API 요청들의 값만 체크하여 request값을 update시켰다.

 

결론

Webflux에 대해 많이 서툴렀기 때문에 이번 과제는 좋은 챌린징이 되었던 것 같다.

작업한 코드가 좋은 코드라고 생각이 들진 않지만,

머릿속으로 생각했던 로직을 구현 해보며 흥미를 느꼈고, Webflux에 대해 공부를 더 해봐야겠다고 느꼈다..!

반응형