首页 > 解决方案 > 轮询弹簧启动执行器端点的更好方法(流式传输而不是轮询?)

问题描述

我正在编写一个 Web UI,它在 Spring Actuator 支持的 Spring Boot 中监视另一个 Java 应用程序。

现在,我可以使用常规 Get 请求(通过 Spring WebFlux 的 WebClient.get() 方法)从其他客户端 Sprint Boot Web 应用程序轮询 Spring Actuator 的端点。

但是,如果某些数据发生变化,比方说指标端点之一(即总是变化的 CPU 使用率),我必须“刷新”获取请求。我可以通过 @Scheduled 注释将它设置在预定的计时器上,但我觉得有更好的方法吗?

我知道如何从不断流动的数据的获取请求中检索通量,但是在服务器上,必须创建通量。Spring Boot Actuator 可以提供一个 Flux 的指标,以便我可以流式传输它吗?

这是一些代码,我目前通过每 500 毫秒 ping 一次的预定方法调用此方法。

private Flux<Health> getHealth(String baseUrl) {

    var fallbackValue = new Health();
    fallbackValue.setStatus("Unknown");
    return webClient.get().uri(baseUrl + "/actuator/health").retrieve().bodyToFlux(Health.class)
            .onErrorReturn(fallbackValue);

}

但它只有在我调用它并使用预定的注释来刷新它时才会更新:

@Scheduled(fixedDelay = 500) // I want to remove this, instead of refreshing, I want the data to stream
public void pollCapHandlers() {

    getHealth("http://localhost:8080").subscribe(health -> {
        ui.access(() -> {
            healthStatusTextField.setValue(health.getStatus()); // this doesn't update in real time
        });
    })

标签: spring-bootspring-webfluxserver-sent-eventsspring-boot-actuatorspring-webclient

解决方案


首先,您应该避免过于频繁地调用执行器端点,尤其是当您的应用程序不使用数据时。如果您的应用程序是仪表板,则除非有人当前正在查看该仪表板,否则它不应该获取数据。这排除了 的使用@Scheduled,无论如何都会发生。此外,执行器数据可以被缓存,或者可以在应用程序上创建一些负载,具体取决于端点。这应该仔细考虑。

现在,您可以在轮询应用程序中以这样的流方式实现这一点:


@GetMapping(path = "/status/{application}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Status> streamStatus() {
  return Flux.interval(interval).flatMap(i -> getHealth(...));
}

这允许您定期轮询远程端点并将结果流式传输到浏览器(使用 SSE),而不会给远程应用程序增加不必要的负载。


推荐阅读