Reactor - как избежать рекурсии?

Используя spring WebFlux, я хотел бы отправлять HTTP-запросы один за другим, пока ответ не будет соответствовать определенным критериям. Мне также нужно собрать все отзывы. В мире блокировок решение будет примерно таким:

List<String> responses = new ArrayList<>();
String lastResponse;
do {
  lastResponse = webClient.get()
    .uri(uri)
    .retrieve()
    .bodyToMono(String.class)
    .block();
  responses.add(lastResponse);
} while(!finished(lastResponse));

Как это реализовать без блокировки?

примечание: есть наивное решение с рекурсией, но я ищу более элегантный способ:

private List<String> collectRemaining() {
  return webClient.get()
    .uri(uri)
    .retrieve()
    .bodyToMono(String.class)
    .flatMap(response -> {
      if(finished(response)) {
        return List.of(response);
      }
      return collectRemaining().flatMap(remaining ->
          Stream.concat(Stream.of(response), remaining.stream()).collect(Collectors.toList());
    });
}

person nagy.zsolt.hun    schedule 10.02.2021    source источник


Ответы (1)


Чтобы заменить рекурсию, вы можете использовать _ 1_, который позволяет сгенерировать следующий элемент на основе предыдущего. Обычно он используется для реализации логики разбивки на страницы. Так что может сработать что-то вроде следующего:

webClient.get()
        .uri(uri)
        .retrieve()
        .bodyToMono(String.class)
        .expand(response -> {
            if (finished(response)) {
                return Mono.empty();
            }
            return webClient.get()
                    .uri(uri)
                    .retrieve()
                    .bodyToMono(String.class);
        }).collectList();

На основе этой статьи.

person Martin Tarjányi    schedule 10.02.2021