Reputation: 267
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
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