Skip to content
Advertisement

spring webclient load balance

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:

  1. 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);
     }
    
  2. 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.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement