如何实现具有来自多个网络客户端的健康信息的反应式健康指示器?

问题描述 投票:0回答:1

我正在尝试实施反应式运行状况指示器来检查多个目标服务的运行状况。

但是,各个服务的 json 没有被解析。我知道 Health 的 Mono 就是 Map 的 Mono。要删除 Map 的 Mono ,如果我使用 block() ,那么它也会失败并出现错误,因为反应式调用中不允许 block() 。我尝试使用 map() 函数并在另一个映射中填充值,但没有值传递给该映射,并且调用者也没有订阅它。由于我使用的是 Spring Boot 执行器,我无法强制调用者订阅,所以我如何在健康检查中实现以下响应

期望的回应

> "reactiveTarget": {
>             "status": "UP"            {
>               "target1": {
>                   "status": "UP"
>               },
>               "target2": {
>                   "status": "UP"
>               }           }
>         },

取得响应

"reactiveTarget": {
            "status": "UP",
            "details": {
                "target1": {
                    "scanAvailable": true
                },
                "holdingsWebClient": {
                    "target2": true
                }
            }
        },

使用的代码

@Component
@Slf4j
public class ReactiveTargetHealthIndicator implements ReactiveHealthIndicator {

    private final ApplicationContext context;

    private String overallStatus="UP";

    public ReactiveTargetHealthIndicator(@NonNull ApplicationContext context) {
        this.context = context;
    }

    @Override
    public Mono<Health> health() {
        return checkTargetServiceHealth().onErrorResume(
                ex -> Mono.just(new Health.Builder().down(ex).build())
        );
    }

    private Mono<Health> checkTargetServiceHealth() {
        var target = this.context;
        Map<String, Mono<Map<String, String>>> targetServiceBeans= new LinkedHashMap<>();
        while (target != null) {
            target.getBeansOfType(WebClient.class)
                    .forEach((name, webclient) -> targetServiceBeans.put(name, createReport(name,webclient)));
            target = target.getParent();
        }
        log.info("Reactive Webclient Beans [{}]", targetServiceBeans); // Bean is empty
        var heathBuilder = new Health.Builder().withDetails(targetServiceBeans);
        return (overallStatus.equals("DOWN") )? Mono.just(heathBuilder.down().build())
                : Mono.just(heathBuilder.up().build());
    }

    private Mono<Map<String, String>> createReport(String name, WebClient webclient) {
        log.info("Reactive Webclient [{}] is triggered", name); // Here name of bean is coming
        return webclient.get()
                .uri("/actuator/health/liveness")
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .bodyToMono(new ParameterizedTypeReference<Map<String, String>>() {
                })
                .onErrorResume(e -> {
                    log.error("Could not retrieve reactive health status of : {}", name, e);
                    overallStatus="DOWN";
                    return Mono.just(Map.of("status", "DOWN"));
                });
    }
}
java spring-boot spring-webflux reactive spring-boot-actuator
1个回答
0
投票

我遇到了类似的问题,问题是你从非反应式上下文中进行反应式操作,例如:map.forEach,通过这样做,你的列表将是一个 MonoDefer 列表,正如你所说,没有人订阅它。

如果你有一个列表,我使用的解决方案是使用 Flux。

你可以尝试这样的事情:

Flux
 .fromIterable(target.getBeansOfType(WebClient.class)) //assuming this gives you a list of something
.flatMap(doYourReactiveOperationThatReturnsAMono())
.last() // you can finish getting the last value emmited for example.

我希望能有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.