[英]spring boot microservice framework how to call another microservice from one microservice
[英]Concurrently call several Spring microservice URLs
我有一个 Spring 引导应用程序,它将使用GET
方法调用多个微服务 URL。 这些微服务 URL 端点都实现为@RestController
。 他们不返回Flux
或Mono
。
我需要我的应用程序来捕获哪些 URL没有返回 2xx HTTP 状态。
我目前正在使用以下代码来执行此操作:
List<String> failedServiceUrls = new ArrayList<>();
for (String serviceUrl : serviceUrls.getServiceUrls()) {
try {
ResponseEntity<String> response = rest.getForEntity(serviceUrl, String.class);
if (!response.getStatusCode().is2xxSuccessful()) {
failedServiceUrls.add(serviceUrl);
}
} catch (Exception e){
failedServiceUrls.add(serviceUrl);
}
}
// all checks are complete so send email with the failedServiceUrls.
mail.sendEmail("Service Check Complete", failedServiceUrls);
}
问题是每个 URL 调用响应缓慢,我必须等待一个 URL 调用完成,然后再进行下一个调用。
如何更改此设置以同时进行 URL 调用? 在所有调用完成后,我需要发送一个 email ,其中包含应在failedServiceUrls
中收集的任何错误 URL。
更新
我将上面的帖子修改为 state,我只想同时进行通话。 我不在乎rest.getForEntity
调用块。
在您的代码中使用执行器服务,您可以通过这种方式并行调用所有微服务:
// synchronised it as per Maciej's comment:
failedServiceUrls = Collections.synchronizedList(failedServiceUrls);
ExecutorService executorService = Executors.newFixedThreadPool(serviceUrls.getServiceUrls().size());
List<Callable<String>> runnables = new ArrayList<>().stream().map(o -> new Callable<String>() {
@Override
public String call() throws Exception {
ResponseEntity<String> response = rest.getForEntity(serviceUrl, String.class);
// do something with the response
if (!response.getStatusCode().is2xxSuccessful()) {
failedServiceUrls.add(serviceUrl);
}
return response.getBody();
}
}).collect(toList());
List<Future<String>> result = executorService.invokeAll(runnables);
for(Future f : result) {
String resultFromService = f.get(); // blocker, it will wait until the execution is over
}
如果您只想同时进行调用并且您不关心阻塞线程,您可以:
Mono#fromCallable
包装阻塞服务调用Flux#fromIterable
将serviceUrls.getServiceUrls()
转换为反应式 streamFlux#filterWhen
使用 2 中的 Flux 和 1 中的异步服务调用同时调用和过滤失败的服务。Flux#collectList
等待所有调用完成并发送 email subscribe
中的 URL 无效void sendFailedUrls() {
Flux.fromIterable(erviceUrls.getServiceUrls())
.filterWhen(url -> responseFailed(url))
.collectList()
.subscribe(failedURls -> mail.sendEmail("Service Check Complete", failedURls));
}
Mono<Boolean> responseFailed(String url) {
return Mono.fromCallable(() -> rest.getForEntity(url, String.class))
.map(response -> !response.getStatusCode().is2xxSuccessful())
.subscribeOn(Schedulers.boundedElastic());
}
使用 Reactor 阻塞调用
由于底层服务调用是阻塞的,它应该在专用线程池上执行。 如果要实现完全并发,这个线程池的大小应该等于并发调用的数量。 这就是为什么我们需要.subscribeOn(Schedulers.boundedElastic())
请参阅: https://projectreactor.io/docs/core/release/reference/#faq.wrap-blocking
使用 WebClient 的更好解决方案
但是请注意,在使用 reactor 和 spring webflux 时应避免阻塞调用。 正确的方法是用 Spring 5 中的WebClient
替换RestTemplate
,这是完全非阻塞的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.