0

I am programming a web UI that monitors another Java application in Spring Boot, supported by Spring Actuator.

Right now I can poll Spring Actuator's endpoints from the other client Sprint Boot web application using a regular Get request (via Spring WebFlux's WebClient.get() method).

But if some data changes, let's say one of the metrics endpoints (i.e. the CPU usage which always changes), I have to "refresh" the get request. I can set it on a scheduled timer via the @Scheduled annotation, but I feel like there's a better way of doing it?

I know how to retrieve a Flux from a get request of constant flowing data, but on the server, a flux has to be created. Can Spring Boot Actuator provide a Flux of the metrics so I can stream it?

Here is some code, I currently call this method via a scheduled method that pings it every 500 ms.

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);

}

But it only updates if I call it and use the scheduled annotation to refresh it always:

@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
        });
    })
Armando Perea
  • 499
  • 2
  • 6
  • 18

1 Answers1

3

First, you should avoid calling the actuator endpoints too often, especially when your application is not using the data. If your application is a dashboard, it should not be fetching the data unless someones is looking at that dashboard currently. This rules out the use of @Scheduled, which happens no matter what. Also, actuator data can be cached, or can create some load on the application, depending on the endpoint. This should be considered carefully.

Now you could achieve that in a streaming fashion like this, in your polling application:


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

This allows you to poll periodically the remote endpoint and stream the result to the browser (with SSE), without adding unnecessary load to remote applications.

Brian Clozel
  • 56,583
  • 15
  • 167
  • 176
  • Thanks, I will try this out. I definitely don't want to use @scheduled, I put that in there as a temporary "hack" until I can do it the right way! :D – Armando Perea Dec 05 '19 at 00:57