Update Service status when service instance is shutdown

730 views Asked by At

I implemented request using Spring Cloud Feign client. I tried this:

Feign client:

@FeignClient(name = "mail-service")
public interface EmailClient {

    @RequestMapping(method = RequestMethod.POST, value = "/register")
    void setUserRegistration(RegisterUserDTO registerUserDTO);

    @RequestMapping(method = RequestMethod.POST, value = "/password_reset")
    void setUserPasswordReset(PasswordResetDTO passwordResetDTO);
}

Feign configuration:

@Configuration
public class LoadBalancerConfiguration {

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

Request DTO:

@Getter
@Setter
public class PasswordResetDTO {

    private int id;
}

Controller:

@Autowire
EmailClient emailClient;

@PostMapping("/dummy")
public ResponseEntity<?> test() {

    RegisterUserDTO obj = new RegisterUserDTO();
    obj.setId(12);

    emailClient.setUserRegistration(obj);

    return ok().build();
}

Feign configuration:

spring:
    cloud:
    loadbalancer:
        ribbon:
            enable: false
feign:
    client:
        config:
            default:
                connectTimeout: 5000
                readTimeout: 5000
                loggerLevel: basic
eureka:
    client:
        serviceUrl:
            defaultZone: ${EUREKA_URI:http://localhost:8761/eureka}
    instance:
        preferIpAddress: true

POM.xml

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-netflix-eureka-client</artifactId>
    </dependency>
    <dependency> 
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    </dependency>

I started 3 instances of endpoint services which are consumed as endpoint from Feign client in a round-robin order. So far so good, it's working as expected. But when I shutdown for example the first service instance the Feign client is not notified of this change and continues to send requests to the inactive service. Do you know how consumer service can be notified when endpoint service is shut down and out of the list of active services? I suppose that I need to configure some health checks?

Do you know how I can solve this issue?

Source code for testing the issue: https://github.com/rcbandit111/eureka-discovery-poc/tree/master

2

There are 2 answers

11
Conscript On

According to the documentation, Ribbon will not do anything to mark the server as down when a request fails, instead it relies on pinging the servers or clients of the load balancer to notify the ribbon by calling markServerDown(Server server).

As a result you should either change the interval of which the ribbon pings the server by providing your own implementation:

public class CustomLoadBalancer {
  @Bean 
  public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
                                          ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
                                          IRule rule, IPing ping) {
      return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList, 
                                         serverListFilter, new PollingServerListUpdater(config));
  }
}

and then use it in your SpringBootApplication configuration like this:

@RibbonClients(defaultConfiguration = CustomLoadBalancer.class)

or you should provide an implementation to call markServerDown(Server) method of ribbon in your client code when you think the time is right.

I suggest you to read this stackoverflow post, I think is directly related to your question.

0
Sreeram Nair On

Ribbon - Load balancer

Out of the box it's providing you with round robin loadbalancing, but you can implement your own @RibbonClient (even for a specific service) and design your custom loadbalancing for example based on eureka metadata. The loadbalancing happens on the client side.

Feign - Http client

With @FeignClient you can rapidly develop clients for you other services (or services outside of your infrastructure). It is integrated with ribbon and eureka so you can refer to your services @FeignClient(yourServiceNameInEureka) and what you end up with is a client which loadbalances between the registered instances with your preferred logic. If you are using spring you can use the familiar @RequestMapping annotation to describe the endpoint you are using.

I have mentioned below example with RandomRule. Also can check Github here for the source.

@RibbonClient(name = "cloud-provider", configuration = CloudProviderConfiguration.class)
public class ConsumerApplication { 
    /* ... */
}

class CloudProviderConfiguration {
    @Bean
    public IRule ribbonRule(IClientConfig config) {
        return new RandomRule();
    }
}

ALso, See the Use of Feign to setup High Availability Load Balancer