2

It's my first time working with webClient and I am wondering how to wait until List<Mono<>> finishes. I have the following code:

List<Address> addresses = collectAllAddresses(someObject);
List<Mono<List<AnotherAddress>>> monoResponses =
        addresses.stream()
                .map(address -> webClientGateway.findAddresses(userData, address.getFullAddress()))
                .collect(Collectors.toList());

Mono.when(monoResponses).block();

log.info("mono responses");
monoResponses.stream()
        .flatMap(it -> Objects.requireNonNull(it.block()).stream()).forEach(it -> log.info("mono responses + {}", it));

and the following findAddresses method:

public Mono<List<AnotherAddress>> findAddresses(UserData userData, String fullAddress) {

    if (StringUtils.isEmpty(fullAddress)) {
        log.info("Address is empty that why we return Mono.just(Collections.emptyList()");
        return Mono.just(Collections.emptyList());
    }

    return webClient.get()
            .uri(path, uri -> uri.queryParam("query", fullAddress).queryParam("count", 1).build())
            .header("someHeader", someHeader)
            .retrieve()
            .bodyToMono(new ParameterizedTypeReference<List<AnotherAddress>>() {
            })
            .doOnError(e -> log.error("Error occurred!", e));
}

but every time I execute it I always get list of empty objects, I mean I get List but every object in that list is empty (every field of class AnotherAddress is null). What can be wrong?

UDP: more explanations: I have two microservices. In one microservice (that return another address) there is RestController that sends anotherAddress. In another microservice I want to use WebClient (instead of using threadPool with many threads) to call the RestController from previous microservice. When I have previous implementation for function webClientGateway.findAddresses(userData, address.getFullAddress()) and it returns Mono<List> I tested it and immediately after calling function I call block on result and it works. But now I have following situation, I have many addresses (maybe 5 or 10) and I want send async request for every address and wait until latest finishes and after that I want to do another operation, but instead of getting fullfielded AnotherAddress instance, I am getting 5 empty AnotherAddress instances (every field is null)

Nick
  • 117
  • 1
  • 10

1 Answers1

1

Use a Flux instead of a Mono, e.g. something like (untested):

public Flux<AnotherAddress> findAddresses(UserData userData, String fullAddress) {

    if (StringUtils.isEmpty(fullAddress)) {
        log.info("Address is empty that why we return Mono.just(Collections.emptyList()");
        return Flux.empty();
    }

    return webClient.get()
            .uri(path, uri -> uri.queryParam("query", fullAddress).queryParam("count", 1).build())
            .header("someHeader", someHeader)
            .retrieve()
            .bodyToFlux(AnotherAddress.class)
            .doOnError(e -> log.error("Error occurred!", e));
}

If you don't need the AnotherAddress list grouped by address the you could use something like (untested):

Flux<AnotherAddress> anotherAddressFlux= Flux.fromIterable(addresses)
                .flatMap(address -> webClientGateway.findAddresses(userData, address.getFullAddress()));

If you want to block you can use:

List<AnotherAddress> anotherAddressList = anotherAddressFlux.collectList().block();
Puce
  • 37,247
  • 13
  • 80
  • 152
  • Unfortunately, it doesn't help, I think we have problem with the infrastructure, because we using "webClient" for calling feign rest endpoint in another microservice, i will investigate how many request will be send and how many answers will be emitted. – Nick Nov 18 '20 at 12:04
  • Now I see, we are not waiting answers from another microservice and emit asnwer with empty fields (I saw it by Kibana) – Nick Nov 19 '20 at 06:51
  • I made a mistake, it seems that timing is correct, but there are milliseconds between answers – Nick Nov 19 '20 at 07:06
  • @Nick I'm not sure I understand what you mean. Please update your question with more details. – Puce Nov 19 '20 at 11:47
  • I was wrong again (see https://stackoverflow.com/questions/57686462/if-i-use-a-reactive-client-should-the-server-be-reactive-too), but the solution that you suggested, doesn't work neither, I cannot find the reason – Nick Nov 19 '20 at 12:40
  • @Nick Please describe in your question exactly what you've tried and what error/ result (actual vs expected) you've got. – Puce Nov 19 '20 at 12:53
  • I added more explanations – Nick Nov 19 '20 at 13:49
  • your answer is right, I had problem with deserialization, also this https://stackoverflow.com/questions/51449889/block-blockfirst-blocklast-are-blocking-error-when-calling-bodytomono-afte can help. Thank you! – Nick Nov 27 '20 at 06:16