본문 바로가기
스프링부트

webFlux 사용기

by 플라퉁 2023. 12. 27.
728x90
반응형

 

 

 

 

 

안녕하세요 오늘은 웹플럭스에서 사용할 수 있는 기능들을 리뷰해 보겠습니다.

 

https://rhgustmfrh.tistory.com/90

 

Spring WebFlux 시작하기 - 리액티브 웹 애플리케이션 개발과 R2DBC 소개

안녕하세요 오늘은 Spring WebFlux에 대해 알아보겠습니다. 지금까지 Spring MVC 어플리케이션을 많이 사용해 왔는데 WebFlux는 이와 대비되는 리액티브 웹 어플리케이션으로써 비동기 통식 방식을 사용

rhgustmfrh.tistory.com

 

웹플럭스에 대한 간단한 소개를 참고하시려면 해당 글에서 확인 하실 수 있습니다.

 

 

1. .doFinally() 와 .then() 의 차이 

 

doFinally는 리액티브 스트림이 완료되거나,

 

에러가 발생했을 때 호출되는 콜백 메서드입니다.

 

이 메서드는 스트림의 최종 상태를 인자로 받아서 사이드 이펙트를 수행합니다.

 

그러나 doFinally는 리턴 값을 제공하지 않습니다.

 

그것은 Mono나 Flux를 변환하거나 생성하는 것이 아니라,

 

해당 스트림의 종료 시점에 어떤 동작을 수행할 것인지를 정의합니다.

 

 

 

then 메서드는 원래의 스트림이 완료되면 실행되는 연산자입니다.

 

이 메서드는 원래의 스트림의 결과를 무시하고,

 

새로운 Mono 또는 Flux를 반환합니다.

 

then 메서드는 주로 원래의 스트림의 완료 시그널을 기다린 후,

 

새로운 동작을 수행하는데 사용됩니다.

 

예를 들어, 데이터베이스에 데이터를 저장한 후,

 

다른 작업을 수행하려는 경우에 사용할 수 있습니다.

 

 

doFinally와 then은 둘 다 리액티브 스트림이 완료될 때 수행되는 동작을 정의하는 메서드이지만,

 

그들이 사용되는 방식과 목적이 다릅니다.

 

doFinally: 이 메서드는 스트림이 종료될 때 (성공적으로 완료되거나, 에러가 발생하거나, 취소되거나)

호출되는 콜백 함수를 등록합니다.

이 메서드는 사이드 이펙트를 수행하는데 사용되며,

원래의 스트림을 변형하지 않습니다.

예를 들어, 리소스를 해제하는 데 사용할 수 있습니다.

doFinally는 원래의 스트림을 반환합니다.

 

then: 이 메서드는 원래의 스트림이 완료될 때 수행되는 동작을 정의하지만,

원래의 스트림의 결과를 무시하고 새로운 Mono 또는 Flux를 반환합니다.

이 메서드는 원래의 스트림이 완료된 후에 새로운 동작을 수행하려는 경우에 사용됩니다.

 

요약하자면, doFinally는 스트림이 종료될 때 사이드 이펙트를 수행하는데 사용되며,

 

원래의 스트림을 변형하지 않습니다.

 

반면에 then은 원래의 스트림이 종료된 후에 새로운 동작을 수행하려는 경우에 사용되며,

 

새로운 Mono 또는 Flux를 반환합니다.

 

다음은 예제입니다.

 

flux.doFinally(signalType -> {
    // 리소스 정리 코드
})

Mono.just("Hello")
    .doOnNext(System.out::println)
    .then(Mono.just("World"))
    .doOnNext(System.out::println);
결과 : Hello
      World

 

 

 

 

2. 재시도 함수 .retryWhen()

 

 

Reactive Streams 프로그래밍에서 에러가 발생했을 재시도 로직을 결정하기 위해 사용됩니다.

 

함수는 에러가 발생할 때마다 호출되며, 어떤 조건에서 재시도할지 결정하는 로직을 제공합니다.

 

.retryWhen() 함수는 Flux 또는 Mono에서 에러가 발생했을 호출되며,

 

인자로 Function 받습니다. Function Flux<Throwable> 인자로 받아 Publisher<?> 반환합니다.

 

Flux<Throwable> 에러가 발생할 때마다 이벤트를 발생시키는 Flux이며,

 

Publisher<?> 재시도를 결정하는 시그널을 제공하는 Publisher입니다.

 

예를 들어, 다음은 최대 3번의 재시도를 수행하는 예제입니다.

 

Flux.range(1, 5)
    .map(i -> {
        if (i <= 3) throw new RuntimeException("Got to 3");
        return i;
    })
    .retryWhen(errors -> errors.zipWith(Flux.range(1, 3), (n, i) -> i))
    .subscribe(System.out::println);

 

 

저는 해당 함수를 실전에서 웹요청 재시도 로직에 삽입하였습니다. 

 

webclient.post()
  ...생략
  .doOnError(throwable -> {
                log.error("Token Request Error : {}", throwable.getMessage());
  //                    result.set(false);
  })
  .retryWhen(Retry.backoff(86400, Duration.ofSeconds(30))
  .filter(throwable -> throwable instanceof Exception)
  .doAfterRetry(retrySignal -> {
  log.info("Token failed after it was just retried...");
  }))
  .block();

 

토큰 요청 로직인데 에러가 발생하면 1일동안 30초마다 webclient.post()부터 다시 시작하게됩니다.

 

재요청후 로그를 확인하기 위해 doAterRetry 메서드를 사용하였고 

 

.block()을 쓴 이유는 해당 토큰로직이 완료되어야 나머지 기능들이 동작되어야하기 때문에

 

동기성을 이유로 사용하였습니다.

 

 

 

 

3. Mono에 빈값을 반환할 때 .switchIfEmpty()

 

메소드는 원본 Mono 또는 Flux 아무런 아이템도 방출하지 않을 대체할 Mono 또는 Flux 제공하는데 사용됩니다.

 

.switchIfEmpty() 인자로 Publisher 받으며,

 

Publisher 원본 Mono 또는 Flux 아무런 아이템도 방출하지 않을 대신 방출됩니다.

 

예를 들어, 다음 코드는 .switchIfEmpty() 사용하여 원본 Mono 아무런 아이템도 방출하지 않을 대체할 값을 제공하는 예입니다

 

Mono.justOrEmpty(Optional.empty())
    .switchIfEmpty(Mono.just("Hello, World!"))
    .subscribe(System.out::println);

 

위의 메서드는 내가 작업하던 Mono가 빈값일 때 (기존이면 null point exception이 나는 경우) 처리할 수 있는

 

유용한 메서드입니다.

 

 

감사합니다.

 

 

 

728x90
반응형

댓글