Michel Nagme
Michel Nagme

Reputation: 267

How to use Hystrix with Spring WebFlux WebClients?

I'm using Spring WebFlux with functional endpoints to create an API. To provide the results I want, I need to consume an external RESTful API, and to do that in a async way I'm using a WebClient implementation. It works well and goes like this:

public WeatherWebClient() {
    this.weatherWebClient = WebClient.create("http://api.openweathermap.org/data/2.5/weather");
}

public Mono<WeatherApiResponse> getWeatherByCityName(String cityName) {
    return weatherWebClient
            .get()
            .uri(uriBuilder -> uriBuilder
                                .queryParam("q", cityName)
                                .queryParam("units", "metric")
                                .queryParam("appid", API_KEY)
                                .build())
            .accept(APPLICATION_JSON)
            .retrieve()
            .bodyToMono(WeatherApiResponse.class);
}

As this performs network access, it's a good use case for NetFlix OSS Hystrix. I've tried using spring-cloud-starter-netflix-hystrix, adding @HystrixCommand to the method above, but there's no way to make it trip the circuit, even if I set a bad URL (404) or wrong API_KEY (401).

I thought this could be a problem of compatibility with the WebFlux itself, but setting property @HystrixProperty(name="circuitBreaker.forceOpen", value="true") indeed forces the fallback method to run.

Am I missing something? Is this approach incompatible with Spring WebClients?

Thanks!

Upvotes: 11

Views: 7103

Answers (1)

Alex Derkach
Alex Derkach

Reputation: 759

@HystrixCommand won't really work, because Hystrix doesn't threat Mono/Flux any different from Java primitives.

Hystrix doesn't monitor content of Mono, but only the result of call public Mono<WeatherApiResponse> getWeatherByCityName(String cityName).

This result is always OK, because reactive-call-chain creation will always succeed.

What you need, is to make Hystrix threat Mono/Flux differently. In Spring Cloud, there is a builder, to wrap Mono/Flux with HystrixCommand.

Mono<WeatherApiResponse> call = this.getWeatherByCityName(String cityName);

Mono<WeatherApiResponse> callWrappedWithHystrix = HystrixCommands
                                .from(call)
                                .fallback(Mono.just(WeatherApiResponse.EMPTY))
                                .commandName("getWeatherByCityName")
                                .toMono();

Upvotes: 20

Related Questions