모종닷컴

Reactor3's SwitchIfEmpty with lazy evaluation.. 본문

Programming

Reactor3's SwitchIfEmpty with lazy evaluation..

모종 2023. 3. 10. 23:23
반응형

Reactor3의 switchIfEmpty 함수를 쓰면서 의도치 않은 버그를 만들게 되면서 관련 이슈 포스팅을 간단하게 하려고 합니다. 

버그 코드

@Test
fun `버그 코드`() {
    Mono.just("monny.tistory.com")
        .doOnNext { println("doOnNext -> $it") }
        .switchIfEmpty(handle())
        .map {
            println("map -> $it")
            it.uppercase()
        }
        .subscribe { println("result -> $it") }
}

private fun handle(): Mono<String> {
    println("handle")
    return Mono.just("handle")
}

먼저 버그코드입니다. Mono에 이미 element를 가지고 있는 상태로 실행하기 때문에 switchIfEmpty는 당연히 실행이 안될 것이라고 생각했었습니다. 실제 위 코드를 실행했을 때 결과는 아래와 같습니다.

뜬금없이 handle이 실행되었다는 것을 알 수 있었습니다. 그것도 순서가 굉장히 수상합니다. 어디서 많이 본듯한 현상인데 eager evaluation 현상입니다.

Lazy Evaluation으로 바꾸자

lazy..

위의 코드에 lazy evaluation을 적용하기 위해서 supplier를 제공해 주면 됩니다. reactor에 fromSupplier나 defer 등 Supplier를 이용할 수 있는 함수가 있는데 지금은 defer가 적절해 보입니다.

@Test
fun `lazy evaluation 적용`() {
    Mono.just("monny.tistory.com")
        .doOnNext { println("doOnNext -> $it") }
        .switchIfEmpty(Mono.defer { handle() })
        .map {
            println("map -> $it")
            it.uppercase()
        }
        .subscribe { println("result -> $it") }
}

이제 handle이 바로 호출이 되지 않고 실제 실행시점에 호출이 되는 것으로 바뀌었습니다. 따라서 handle 메서드는 실행이 되지 않았습니다. 아래는 element를 주지 않고 실행시켰을 때 결과입니다. handle이 제 순서에 실행되고 있습니다.

@Test
fun `lazy evaluation 적용2`() {
    Mono.empty<String>()
        .doOnNext { println("doOnNext -> $it") }
        .switchIfEmpty(Mono.defer { handle() })
        .map {
            println("map -> $it")
            it.uppercase()
        }
        .subscribe { println("result -> $it") }
}
반응형