首页 > 解决方案 > 从 Mono.first 发出第一个成功的结果

问题描述

我有两个Monos 要么返回 a404要么产生 a result

我怎样才能将这两个Monos结合起来

我试过了

      Mono<Result> mono0 = client.get()
          .uri(uri1)
          .retrieve()
          .bodyToMono(Result.class)
          .onErrorResume(e -> Mono.never());

      Mono<Result> mono1 = client.get()
          .uri(uri2)
          .retrieve()
          .bodyToMono(Result.class)
          .onErrorResume(e -> Mono.never());

      return Mono.first(mono0, mono1)
          .blockOptional()

这种方法的问题是,如果两者都Mono产生错误,它永远不会完成......

我想我需要像OnErrorDetach......!?

为了使问题更清楚,我创建了一个 TestCase:

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import java.util.Optional;

import org.junit.jupiter.api.Test;

import reactor.core.publisher.Mono;

class DummyTest {

  public Optional<String> getResult(Mono<String> m1, Mono<String> m2) {
    return Mono.first(m1, m2)
        // DoSomethingHere ?!??!?
        .blockOptional();
  }

  @Test
  void testFirstSuccessfullAndSecondErrorMono() {
    Optional<String> result = getResult(Mono.just("Something"), Mono.error(new RuntimeException()));

    assertThat(result, is(Optional.of("Something")));
  }

  @Test
  void testSecondSuccessfullAndFirstErrorMono() {
    Optional<String> result = getResult(Mono.error(new RuntimeException()), Mono.just("Something"));

    assertThat(result, is(Optional.of("Something")));
  }

  @Test
  void testTwoErrorMonosYieldEmpty() {
    Optional<String> result =
        getResult(Mono.error(new RuntimeException()), Mono.error(new RuntimeException()));

    assertThat(result, is(Optional.empty()));
  }


}


标签: javaspring-webfluxproject-reactor

解决方案


问题Mono.first()在于它需要第一个信号(不是第一个值),因此您最终会尝试Mono永远延迟相应的信号以使其不重播完成信号。相反,您希望某些东西取第一个

而不是.onErrorResume(e -> Mono.never());,使用.onErrorResume(e -> Mono.empty());. 然后你可以使用:

Flux.merge(mono0, mono1).next();

merge()与相对concat()next()应确保采用第一个值而忽略另一个值。blockOptional()如果你愿意,你当然也可以。


推荐阅读