[Spring] Utilize spring web client

Since WebClient replace RestTemplateĀ  to call external API in Spring. There are some patrices I lesson learnt in my work and summarize as below.

There is a sample service to call API to get data from external API. To simpify it, we skip HTTPS and token authentication in here.

import local.poc.webclientpool.models.EmployeeResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;

import javax.annotation.PostConstruct;
import java.time.Duration;


@Service
public class EmployeeService {
    @Value("${tourist-service-base-url}")
    private String touristServiceBaseUrl;
    @Value("${tourist-service-max-concurrent-call}")
    private int maxConcurrentCall;
    @Value("${default-queue-size}")
    private int maxQueueSize;
    @Value("${default-timeout-second}")
    private int timeoutInSecond;
    @Value("${default-retry-interval}")
    private int retryInterval;
    private Scheduler scheduler;

    @PostConstruct
    void postConstruct() {
        scheduler = Schedulers.newBoundedElastic(maxConcurrentCall, maxQueueSize, "EmployeeServiceThreadGroup");
    }

    public Mono<EmployeeResponse> getEmployees() {
        WebClient webClient = WebClient.builder()
                .baseUrl(touristServiceBaseUrl)
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .build();
        return webClient.get()
                .uri(uriBuilder -> {
                    return uriBuilder.path("employees")
                            .queryParam("page", 1)
                            .build();
                })
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .bodyToMono(EmployeeResponse.class)
                .publishOn(scheduler)
                .retryWhen(Retry.backoff(retryInterval, Duration.ofSeconds(timeoutInSecond)))
                .timeout(Duration.ofSeconds(timeoutInSecond))
                ;
    }
}

 

  1. Assign elastic scheduler;
    Most of the external APIs are required limited concurrent call; It might return HTTP 423 (Too many request) if haven’t proper control. To prevent this situation, it can add elastic scheduler to set the call limit and execution timeout.
    In the example, the scheduler has been initialize in method postConstruct() and assign to webClient method publishOn() .
  2. Add timeout;
    In order to prevent resource consume to hold HTTP request, suggest add timeout to release resource if running a long time.
    In this example timeout was assign in webclientĀ  timeout().
  3. Add retry;
    For soma instable network environment, HTTP response might cannot get response properly. using RetryWhen() can enable retry in case failure. Also, it use backoff() to prevent multi thread concurrent retry.
About C.H. Ling 262 Articles
a .net / Java developer from Hong Kong and currently located in United Kingdom. Thanks for Google because it solve many technical problems so I build this blog as return. Besides coding and trying advance technology, hiking and traveling is other favorite to me, so I will write down something what I see and what I feel during it. Happy reading!!!

Be the first to comment

Leave a Reply

Your email address will not be published.


*


This site uses Akismet to reduce spam. Learn how your comment data is processed.