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)) ; } }
- 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, thescheduler
has been initialize in methodpostConstruct()
and assign towebClient
methodpublishOn()
. - 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 webclienttimeout()
. - Add retry;
For soma instable network environment, HTTP response might cannot get response properly. usingRetryWhen()
can enable retry in case failure. Also, it usebackoff()
to prevent multi thread concurrent retry.
Leave a Reply