Создайте первый успешный результат от Mono.first - PullRequest
1 голос
/ 10 марта 2020

У меня есть два Mono с, которые либо возвращают 404, либо дают result.

Как я могу объединить эти два Mono с

  • result испускается, как только один из Mono s завершается успешно.
  • и Optional.empty возвращаются, как только все Mono s выдают 404 или сталкиваются с какой-либо другой ошибкой?

Я пытался

      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 s приведут к ошибке ...

Я думаю, что я нужно что-то вроде 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()));
  }


}


1 Ответ

0 голосов
/ 10 марта 2020

Проблема с Mono.first() состоит в том, что он принимает первый сигнал (не первое значение), так что вы в конечном итоге пытаетесь отложить соответствующий Mono навсегда, чтобы заставить его не воспроизводить завершение сигнал. Вместо этого вы хотите, чтобы что-то приняло первое значение .

Вместо .onErrorResume(e -> Mono.never());, используйте .onErrorResume(e -> Mono.empty());. Затем вы можете использовать:

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

merge() (в отличие от concat()) в сочетании с next() должно гарантировать, что первое значение будет взято, а другое проигнорировано. Вы можете, конечно, все еще blockOptional(), если вы будете sh.

...