轮询 spring 引导执行器端点的更好方法(流式传输而不是轮询?)
Better way to poll spring boot actuator endpoint (stream it instead of polling?)
我正在编写一个 Web UI,它在 Spring 引导中监视另一个 Java 应用程序,由 Spring Actuator 支持。
现在我可以使用常规 Get 请求(通过 Spring WebFlux 的 WebClient.get() 方法)从其他客户端 Sprint Boot Web 应用程序轮询 Spring Actuator 的端点。
但是如果某些数据发生变化,比如说指标端点之一(即 CPU 用法总是在变化),我必须 "refresh" 获取请求。我可以通过 @Scheduled 批注将其设置在预定的计时器上,但我觉得有更好的方法吗?
我知道如何从持续流动数据的获取请求中检索 Flux,但在服务器上,必须创建一个 flux。 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
});
})
首先,您应该避免过于频繁地调用执行器端点,尤其是当您的应用程序不使用数据时。如果您的应用程序是一个仪表板,它不应该获取数据,除非当前有人正在查看该仪表板。这排除了 @Scheduled
的使用,无论如何都会发生。此外,执行器数据可以被缓存,或者可以在应用程序上创建一些负载,具体取决于端点。这个要慎重考虑。
现在您可以在轮询应用程序中以这样的流式方式实现:
@GetMapping(path = "/status/{application}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Status> streamStatus() {
return Flux.interval(interval).flatMap(i -> getHealth(...));
}
这允许您定期轮询远程端点并将结果流式传输到浏览器(使用 SSE),而不会给远程应用程序增加不必要的负载。
我正在编写一个 Web UI,它在 Spring 引导中监视另一个 Java 应用程序,由 Spring Actuator 支持。
现在我可以使用常规 Get 请求(通过 Spring WebFlux 的 WebClient.get() 方法)从其他客户端 Sprint Boot Web 应用程序轮询 Spring Actuator 的端点。
但是如果某些数据发生变化,比如说指标端点之一(即 CPU 用法总是在变化),我必须 "refresh" 获取请求。我可以通过 @Scheduled 批注将其设置在预定的计时器上,但我觉得有更好的方法吗?
我知道如何从持续流动数据的获取请求中检索 Flux,但在服务器上,必须创建一个 flux。 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
});
})
首先,您应该避免过于频繁地调用执行器端点,尤其是当您的应用程序不使用数据时。如果您的应用程序是一个仪表板,它不应该获取数据,除非当前有人正在查看该仪表板。这排除了 @Scheduled
的使用,无论如何都会发生。此外,执行器数据可以被缓存,或者可以在应用程序上创建一些负载,具体取决于端点。这个要慎重考虑。
现在您可以在轮询应用程序中以这样的流式方式实现:
@GetMapping(path = "/status/{application}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Status> streamStatus() {
return Flux.interval(interval).flatMap(i -> getHealth(...));
}
这允许您定期轮询远程端点并将结果流式传输到浏览器(使用 SSE),而不会给远程应用程序增加不必要的负载。