springspring-cloudnetflix-eurekaspring-cloud-loadbalancer

Load balancer does not contain an instance for the service


I want to use Eureka client with spring-cloud-starter-loadbalancer. But when I added configuration I get error. When I remove @LoadBalancerClient(name = "mail-service", configuration = LoadBalancerConfiguration.class) and LoadBalancerConfiguration class configuration it's working fine. I tried this code:

    @FeignClient(name = "mail-service")
    @LoadBalancerClient(name = "mail-service", configuration = LoadBalancerConfiguration.class)
    public interface EmailClient {
    
        @RequestMapping(method = RequestMethod.POST, value = "/engine/emails/register")
        void setUserRegistration(CreateUserDTO createUserDTO);
    }


@Configuration
public class LoadBalancerConfiguration {

    @Bean
    public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
                .withBlockingDiscoveryClient()
                .withSameInstancePreference()
                .withHealthChecks()
                .build(context);
    }
}

application.yml:

feign:
    client:
        config:
            default:
                connectTimeout: 5000
                readTimeout: 5000
                loggerLevel: basic
eureka:
    client:
        serviceUrl:
            defaultZone: ${EUREKA_URI:http://localhost:8761/eureka}
        fetchRegistry: true
        healthcheck:
            enabled: true
    instance:
        preferIpAddress: true
        leaseRenewalIntervalInSeconds: 10

POM.xml dependencies

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>com.netflix.eureka</groupId>
        <artifactId>eureka-core</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    </dependency>

I get this error when I have only one target service.

[503] during [POST] to [http://mail-service/engine/emails/register] [EmailClient#setUserRegistration(CreateUserDTO)]: [Load balancer does not contain an instance for the service mail-service]

I use Release Train Version: 2020.0.3

Do you know what could be the problem?


Solution

  • Any application using load balancer should follow the below order

    1. Start the Eureka Server
    2. Start the instances of the Service one by one which have dependency

    Any application relies on information from a service registry (i.e. Eureka). Until the application is registered with it's instances by the serviceId , the Eureka server will not be able to pick that instance while load-balancing.

    In the code you have shared, the bean ServiceInstanceListSupplier is created in the configuration class along with the health checks ( .withHealthChecks() ). This is causing the application to fail as service has not been registered yet.

    Also, the LoadBalancer config should not be in a @Configuration-annotated class instead, it should be a class passed for config via @LoadBalancerClient or @LoadBalancerClients annotation, as described here.

    The only bean you need to instantiate is the ServiceInstanceListSupplier (if you add spring-cloud-starter-loadbalancer, LoadBalancerClientFactory etc. will be instantiated by the starter itself).

    So your LoadBalancer configuration class should look like code below. It should not be in the @Configuration class:

    public class LoadBalancerConfiguration {
    
    @Bean
    public ServiceInstanceListSupplier instanceSupplier(ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
                .withDiscoveryClient()
                .withHealthChecks()
                .build(context);
    }
    

    }

    As explained in this link, the actual @Configuration class , will have the following annotation: @LoadBalancerClients(defaultConfiguration = LoadBalancerConfiguration .class).

    Then, if you enable health-checks in the instances, it should work without any issues.