ABOUT ME

Today
Yesterday
Total
  • Mono.zipWith 혹은 Mono.zipWhen이 호출되지 않을 때
    TECH/Java 2022. 10. 23. 19:43

    소스 Mono가 empty이거나 Mono<Void>인 경우, 일부 조합은 절대 호출되지 않을 수 있다.

     

    정의에 따르면 소스에서 결과물을 만들어 내기 위해 요소가 필요한 zip, zipWith, zipWhen와 같은 transformer(변환 연산자)에서 흔히 발생하는 일이다.

     

    따라서 data-supressing 오퍼레이터를 zip에 사용하는 것은 문제가 된다.

     

    data-supressing operators 예시

    • then
    • thenEmpty(Publisher<Void>)
    • ignoreElements
    • ignoreElement()
    • when(Publisher)

     

    설명이 잘 와닿지가 않는데, 간단하게 예시를 통해 살펴보자.

        @Test
        void test1() {
            StepVerifier.create(Mono.empty() // 1 ... empty 사용
                .zipWith(Mono.just("test data")))
                .expectNextCount(0)
                .verifyComplete();
    
            StepVerifier.create(methodReturnsMonoVoid()
            .zipWith(Mono.just("test data")))
                .expectNextCount(0)
                .verifyComplete();
        }
    
        public Mono<Void> methodReturnsMonoVoid() {
            return Mono.just("this method returns Mono<Void>")
                .then(); // 2 ... data supressing operator 사용
        }

     

    1의 경우 Mono의 Source가 empty 이기 때문에 zipWith가 호출되지 않는다.
    2의 경우 Mono가 data supressing operator인 `then()` 을 사용하였고, 이로 인해 zipWith가 호출되지 않는다.

     

    유사하게, flatMap과 같이 동작을 변경하기 위해 Function<T, ?>를 사용하는 operator는 Function을 적용할 수 있도록 최소 하나 이상의 emit된 아이템을 필요로 한다. 이 함수를 empty (or <Void>) 시퀀스에 적용하는 것은 절대 element를 만들어내지 못한다.

    StepVerifier.create(methodReturnsMonoVoid() // Mono<Void>를 리턴한다.
                .flatMap(unused -> new Mono<Void>() {
                    @Override
                    public void subscribe(CoreSubscriber<? super Void> actual) {
                        System.out.println("this is never called.");
                    }
                }))
                .expectNextCount(0)
                .verifyComplete();
    Mono<Void>를 리턴했기 때문에 이어진 flatMap은 호출되지 않는다.

     

    T 타입의 빈 시퀀스를 기본 값이나 fallback Publisher<T>로 대체하기 위해 .defaultIfEmpty(T) 그리고 .switchIfEmpty(Publisher<T>)를 사용할 수 있는데, 이는 이러한 상황을 피하도록 도와준다.

    StepVerifier.create(Mono.empty()
                .switchIfEmpty(Mono.just("test1")) // empty 인 경우 값을 대체 
                .zipWith(Mono.just("test2")))
                .consumeNextWith(tuple2 -> {
                    Assertions.assertEquals(tuple2.getT1(), "test1");
                    Assertions.assertEquals(tuple2.getT2(), "test2");
                })
                .verifyComplete();

     

    하지만 이 함수들은 Flux<Void>/Mono<Void>에 적용할 수 없다는 점에 주의하자. 여전히 empty여야 하는 다른 Publisher<Void>로 바꾸는 것만 가능하기 때문이다.

    StepVerifier.create(methodReturnsMonoVoid()
                .switchIfEmpty(Mono.empty())
                .zipWith(Mono.just("test2")))
                .expectNextCount(0)
                .verifyComplete();
    대체로 사용하는 값도 empty이기 때문에 zipWith는 호출되지 않는다.

     

    원본 : https://projectreactor.io/docs/core/release/reference/#faq.monoThen

Designed by Tistory.