Search code examples
javafallbackhystrixspring-cloud-feignfeign

Issue in getting cause in HystrixFeign client fallback


I have the HystrixFeign client and I am trying to get the cause/exception in my fallback implementation, because I would really like to know the reason for fallback so I can fix the issue why the service call has failed. But the below implementations are not getting me the cause. This works just fine and the fallback is getting called all the time. But I have no clue why. I am new to Feign and Hystrix. My application is written in java 1.6 years back and this is kind of enhancement call. So I cant go for any lambda expressions.

I have the client interface defined like below

public interface MyServiceFeignClient {
      @RequestLine("POST /myService/order")
      @Headers("Content-Type:application/vnd.org.company.domain.order+json;version=1.0")
      ServiceResponse sendOrder(String content);
}

My FeignClientFacory is like below

public class FeignClientFactory {

    private static final Logger LOG = LoggerFactory.getLogger(FeignClientFactory.class);

    private String serviceUrl;

    public FeignClientFactory(final String serviceUrl) {
        this.serviceUrl = serviceUrl;
    }

    public MyServiceFeignClient newInstance() {
        return HystrixFeign.builder()
            .decoder(new GsonDecoder())
            .target(MyServiceFeignClient.class, serviceUrl);

    }

    class ClientFallbackFactory implements MyServiceFeignClient, FallbackFactory<ClientFallbackFactory> {

        final Throwable cause;

        public ClientFallbackFactory() {
            this(null);
        }

        ClientFallbackFactory(Throwable cause) {
            this.cause = cause;
        }
        // note that this method is not getting called at all
        @Override
        public ClientFallbackFactory create(Throwable cause) {
            if (cause != null) {
                String errMessage = StringUtils.isNotBlank(cause.getMessage()) ? cause.getMessage() : "unknown error occured";
                LOG.debug("Client fallback called for the cause : {}", errMessage);
            }
            return new ClientFallbackFactory(cause);

        }
        // everytime this method is called as fallback and the cause is just null
        @Override
        public ServiceResponse sendOrder(String content) {
            LOG.debug("service client api fallback called");
            ServiceResponse response = new ServiceResponse();
            String errMessage = (cause == null ? "service client api fallback called" : cause.getMessage());
            response.setErrorMessage(errMessage);
            response.setResultStatus("WARN");
            return response;
        }

    }

}

Solution

  • Taking the retroApi example test case code from open feign git hub and start modifying one by one helped me fix the issue. Below is the working code.

    public static class ClientFallbackFactory implements MyServiceFeignClient, FallbackFactory<ClientFallbackFactory> {
    
        @Override
        public ClientFallbackFactory create(Throwable cause) {
            return new PRSClientFallback(cause);
        }
    
        final Throwable cause; // nullable
    
        public ClientFallbackFactory() {
            this(null);
        }
    
        ClientFallbackFactory(Throwable cause) {
            this.cause = cause;
        }
    
        @Override
        public PaymentRiskServiceResponse sendOrder(String content) {
            String errorMessage = (cause == null) ? "No cause returned" : cause.getMessage();
            LOG.debug("Client fallback called : {} ", errorMessage);
            MyServiceResponse response = new MyServiceResponse();
            response.setResultStatus("WARN");
            response.setErrorMessage("Client fallback called");
            return response;
        }
    }
    

    Make sure to type cast the Fallback factory, while invoking the HystrixFeign target method, because the Fallback class is implementing both your client interface and the FallbackFactory.

    return HystrixFeign.builder()
            .encoder(new JacksonEncoder(mapper))
            .decoder(new GsonDecoder())
            .target(MyServiceFeignClient.class, prsUrl, (FallbackFactory<ClientFallbackFactory>) new ClientFallbackFactory());
    

    You can track the conversation of this issue [https://github.com/OpenFeign/feign/issues/458]