Never used webclient with load balancing before and I fallowed https://spring.io/guides/gs/spring-cloud-loadbalancer/ and implemented webclient load balancer, now I am trying to use helthchecks and having problem.
@Bean
@Primary
ServiceInstanceListSupplier serviceInstanceListSupplier(ConfigurableApplicationContext ctx) {
return ServiceInstanceListSupplier
.builder()
.withRetryAwareness()
.withHealthChecks()
.withBase(new RestCaller("restCaller"))
.build(ctx);
}
and I got the error below
2021-06-27 17:32:01.562 WARN 12252 --- [ parallel-4] o.s.c.l.core.RoundRobinLoadBalancer : No servers available for service: httpbin.org
2021-06-27 17:32:01.564 WARN 12252 --- [ parallel-4] eactorLoadBalancerExchangeFilterFunction : LoadBalancer does not contain an instance for the service httpbin.org
2021-06-27 17:32:01.606 WARN 12252 --- [ parallel-4] o.s.c.l.core.RoundRobinLoadBalancer : No servers available for service: httpbin.org
2021-06-27 17:32:01.606 WARN 12252 --- [ parallel-4] eactorLoadBalancerExchangeFilterFunction : LoadBalancer does not contain an instance for the service httpbin.org
2021-06-27 17:32:01.607 WARN 12252 --- [ parallel-4] o.s.c.l.core.RoundRobinLoadBalancer : No servers available for service: httpbin.org
2021-06-27 17:32:01.607 WARN 12252 --- [ parallel-4] eactorLoadBalancerExchangeFilterFunction : LoadBalancer does not contain an instance for the service httpbin.org
2021-06-27 17:32:01.607 WARN 12252 --- [ parallel-4] o.s.c.l.core.RoundRobinLoadBalancer : No servers available for service: restCaller
2021-06-27 17:32:01.608 WARN 12252 --- [ parallel-4] eactorLoadBalancerExchangeFilterFunction : LoadBalancer does not contain an instance for the service restCaller
when I comment "withHealthChecks()" everything works as expected. My main target is to disable the "DefaultServiceInstance" in case it is failing (means http status 503 or 404 or any error).
I prepared a reproducer at https://github.com/ozkanpakdil/spring-examples/tree/master/web-client-loadbalancer just run "mvn test" you will see the error. you can see the configuration at https://github.com/ozkanpakdil/spring-examples/tree/master/web-client-loadbalancer.
Thanks for providing the sample. Have gone through it. There are 2 issues:
The same @LoadBalanced WebClient.Builder
instance is used both for handling the original request and sending health-check requests, so the calls coming out from HealthCheckServiceInstanceListSupplier
are done with a load-balanced Webclient
instead of a non-load-balanced one. Since at this stage the real hosts are being used, a non-load-balanced Webclient
instance should be used for that. You can achieve it by instantiating 2 separate Webclient.Builder
beans in your configuration and using qualifier to pass a non-loadbalanced one to the HealthCheckServiceInstanceListSupplier
, like so:
@Configuration
@LoadBalancerClient(name = "restCaller", configuration = RestCallerConfiguration.class)
public class WebClientConfig {
@LoadBalanced
@Bean
@Qualifier("loadBalancedWebClientBuilder")
WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}
@Bean
@Qualifier("webClientBuilder")
WebClient.Builder webClientBuilder() {
return WebClient.builder();
}
}
@Configuration
public class RestCallerConfiguration {
@Autowired
@Qualifier("webClientBuilder")
WebClient.Builder webClientBuilder;
@Bean
@Primary
ServiceInstanceListSupplier serviceInstanceListSupplier(ConfigurableApplicationContext ctx) {
return ServiceInstanceListSupplier
.builder()
.withRetryAwareness()
.withHealthChecks(webClientBuilder.build())
.withBase(new RestCaller("restCaller"))
.build(ctx);
}
The HealthCheckServiceInstanceListSupplier
sends requests at a health-check URL to verify that the service instance is alive. By default, we assume that the collaborating services have spring-boot-starter-actuator
in their dependencies and the request is being sent at th/actuator/health
endpoint. Since this endpoint is not configured in httpbin
, which the tests use, we get a 404
. Changing the health-check path in properties will fix that:
spring.cloud.loadbalancer.health-check.path.default=/
I have pushed a branch with a fixed config here. If you run the test with this setup, it passes.