3

We are using WebClient to communicate with another service. For the time being (in performance testing) its a mock which returns response after 150 ms.

But in the service, time taken by WebClient is far greater than this. We had set timeout at 250 ms, and in that case we found that less than 1% request where getting timed out. We increased the timeout to check the max time taken by WebClient. In this case we found that latency goes upto 500-600 ms for some requests.

Both the service and mock is in AWS, so there is minimal network latency. We verified it via New Relic too. Our service was getting response in average of about 153 ms.

So the question why WebClient is taking this extra time for some requests. Is this some configuration issue at our end or a known problem in WebClient. How can we solve this?

We are using Spring Boot version 2.2.0.RELEASE with web flux, netty etc being on default versions that are bundled with this spring boot version.

Code that we are using to create WebClient and sending requests:

WebClient webClient;

    @PostConstruct
    public void init() {
        webClient = WebClient.create();
    }

public Mono<?> postRequest(final RequestContext requestContext,
                               final MultiValueMap headers, final MediaType contentType, final MediaType acceptType) {
        Mono<?> response;
        try {
            String url = requestContext.getDownStreamObject().getDownstreamRequestUrl();
            URI uri = new URI(url);
            
            long webClientstartTime = System.currentTimeMillis();
            response = webClient.post().uri(uri)
                    .contentType(contentType)
                    .headers(httpHeaders -> {
                        if (Objects.nonNull(headers)) {
                            httpHeaders.addAll(headers);
                        }
                    })
                    .bodyValue(requestContext.getRequest())
                    .accept(acceptType)
                    .exchange()
                    .timeout(Duration.ofMillis(requestContext.getDownStreamObject().getTimeout()))
                    .doOnSuccess(clientResponse -> log.info("clientResponse.statusCode() : {}, {} , requestId : {}, host : {} ,webClient latency : {}",
                            clientResponse.statusCode(), clientResponse.toString(),requestContext.getRequestId(), uri.getHost(),
                            System.currentTimeMillis() - webClientstartTime))
                    .doOnError(throwable -> {
                        log.error("clientResponse error :{} , requestId :{}, sessionId: {}, host : {}, webclient latency : {}",
                            throwable,requestContext.getRequestId(), requestContext.getServiceId(), uri.getHost(), System.currentTimeMillis() - webClientstartTime);
                    })
                    .flatMap(clientResponse -> clientResponse.bodyToMono(String.class));
            return response;
        } catch (Exception ex) {
            log.error("Some exception while processing post request for requestId :{}, sessionId: {}. Error: {}",
                requestContext.getRequestId(), requestContext.getServiceId(), Utility.exceptionFormatter(ex));
        }
        return null;

    }
Akash
  • 99
  • 6
  • I will strongly recommend you to upgrade your Spring Boot version ... – Violeta Georgieva Feb 03 '22 at 09:24
  • @VioletaGeorgieva thanks sure. But any particular reason? Does this version of spring boot is causing this problem? – Akash Feb 03 '22 at 10:00
  • 1
    There might be fixes that you miss. Check in the latest Spring Framework releases why the `exchange` is deprecated and what are the replacement methods that you should use. – Violeta Georgieva Feb 03 '22 at 11:46
  • Ok sure, thanks. Will try this – Akash Feb 03 '22 at 13:54
  • Have you tried profiling the application and / or running with more memory? I don't know of an underlying reason why some requests would take longer, so I don't think there's an obvious cause here. It could well be related to GC pauses though, in which case profiling would make that obvious. – Michael Berry Feb 04 '22 at 14:41
  • Your catch has no sense there due to flow is not triggered: no call of subscribe() or block(). Also, latency may be calculated with delay depending when flow consumer really enters the game. – Simon Logic Feb 17 '22 at 20:44

0 Answers0