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 fhttps://github.com/ozkanpakdil/spring-examples/tree/master/web-client-loadbalancer.
Advertisement
Answer
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 fromHealthCheckServiceInstanceListSupplier
are done with a load-balancedWebclient
instead of a non-load-balanced one. Since at this stage the real hosts are being used, a non-load-balancedWebclient
instance should be used for that. You can achieve it by instantiating 2 separateWebclient.Builder
beans in your configuration and using qualifier to pass a non-loadbalanced one to theHealthCheckServiceInstanceListSupplier
, 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 havespring-boot-starter-actuator
in their dependencies and the request is being sent at th/actuator/health
endpoint. Since this endpoint is not configured inhttpbin
, which the tests use, we get a404
. 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.