Spring Cloud Consul client does not ignore critical services

702 Views Asked by At

I have implemented a Spring Cloud based application that has the following principal architecture. The GatewayService delegates to multiple instances of HelloService. I use Consul for service discovery. GatewayService is implemented in the following way:

@EnableDiscoveryClient
@SpringBootApplication
public class GatewayApplication {

  public static void main(String[] args) {
    SpringApplication.run(ApiGatewayApplication.class, args);
  }

  @Bean
  @LoadBalanced
  public WebClient.Builder loadBalancedWebClientBuilder() {
    return WebClient.builder();
  }

  @RestController
  static class GateWayController {

    private final WebClient.Builder webClientBuilder;

    @Data
    @NoArgsConstructor
    private static class Response {
      private String message;
      private String appName;
      private int port;
    }

    @Autowired
    public GateWayController(WebClient.Builder webClientBuilder) {
      this.webClientBuilder = webClientBuilder;
    }

    @GetMapping("/lbhello")
    public Mono<Response> hello() {
      return webClientBuilder.build()
                             .get()
                             .uri("lb://hello-service/hello")
                             .retrieve()
                             .bodyToMono(Response.class);
    }
  }
}

spring-cloud-starter-consul-discovery and spring-cloud-starter-loadbalancer areincluded as a dependencies in pom.xml. In application.yaml I only set application.name and disable Ribbon, so that Spring Cloud Loadbalancer is used. When I start the GatewayService and two instances of HelloService everything works as expected. Service calls to the lbhello endpoint are delegated alternately to the two HelloService instances.

When one instance of HelloService is stopped, Consul detects that the instance is missing an marks it as critical. As a consequence I would expect that the load balancer stops forwarding requests to the non-existing service, at least after some time. But this never happens. Every second service call is delegated to this service instance and consequently fails. When using Eureka as a discovery service the registry is adapted and only the remaining HelloService is considered for service calls.

Is this the expected behavior for Consul? If the answer is yes, is there a Spring Cloud setting to adapt this behavior?

1

There are 1 best solutions below

0
On

The Spring Cloud ConsulDiscoveryClient loads all service instance by default, regardless of their health state. This behavior can be changed by the following configuration setting:

spring.cloud.consul.discovery.query-passing = true

With this setting request are not delegated to non-healty instances after some delay.