Feign: Unable to access the cause in FallbackFactory

Created on 8 Sep 2016  Â·  11Comments  Â·  Source: OpenFeign/feign

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, new ClientFallbackFactory());
    }

    static 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";
                // I don't see this log statement
                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;
        }
    }
}

My test case is like below.

    @Test
    public void testSendOrderToPaymentRiskService() {

        String order = loadFile("/order.json");
        ServiceResponse response = client.sendOrder(order);
        // status is always WARN - so fallback is getting called everytime.
        assertThat(response.getResultStatus()).isEqualTo("SUCCESS");
        assertThat(response.getTransactionId()).isNotNull();
        // getting the error message "service client api fallback called"
        assertThat(response.getErrorMessage).isNull();

    }

All 11 comments

in the future, please format your code consistently, as it is hard to read when indenting is all over the place.

I presume this is a copy/paste error?

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

If you are using openfeign (ex latest version is 9.3.1), then you'd need to actually pass the fallback factory, right?

public MyServiceFeignClient newInstance() {
       return HystrixFeign.builder()
            .decoder(new GsonDecoder())
            .target(MyServiceFeignClient.class, serviceUrl, new ClientFallbackFactory() /* <-- this */);
}

Yes sorry my bad. Formatted and fixed the issue.
I added code with in 3 quotes. Like this . I am not sure how I can add with syntax highlighting.

for syntax highlighting

On Thu, Sep 8, 2016 at 10:46 PM, seetharamani <[email protected]>
wrote:

> Yes sorry my bad. Formatted and fixed the issue.
> I added code with in 3 quotes. Like this . I am not sure how I can add
> with syntax highlighting.
>
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub
> <https://github.com/OpenFeign/feign/issues/458#issuecomment-245621868>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AAD615OdUPQ1Zw_piY2fEa0WeNeC7KE_ks5qoB_KgaJpZM4J3-h->
> .
>

Am i missing something here for fallback factory to not work?

Since we have a unit test for this problem, can you try to run that or similar. The unit test works, so it might help you by starting with something that works and then change it until it doesn't.

  // retrofit so people don't have to track 2 classes
  static class FallbackApiRetro implements TestInterface, FallbackFactory<FallbackApiRetro> {

    @Override public FallbackApiRetro create(Throwable cause) {
      return new FallbackApiRetro(cause);
    }

    final Throwable cause; // nullable

    public FallbackApiRetro() {
      this(null);
    }

    FallbackApiRetro(Throwable cause) {
      this.cause = cause;
    }

    @Override public String invoke() {
      return cause != null ? cause.getMessage() : "foo";
    }
  }

  @Test
  public void fallbackFactory_example_retro() {
    server.enqueue(new MockResponse().setResponseCode(500));

    TestInterface api = target(new FallbackApiRetro());

    assertThat(api.invoke()).isEqualTo("status 500 reading TestInterface#invoke()");
  }

https://github.com/OpenFeign/feign/blob/master/hystrix/src/test/java/feign/hystrix/FallbackFactoryTest.java#L102

ps if you end up not being able to pin down with above hint, ping back

Thanks for the suggestion Adrian. I did run the FallbackApiRetro and it works fine in my local. It works even when I point to my actual service instead of mock service. Weird thing is my maven build is keep failing with below error.

reference to target is ambiguous
[ERROR] both method <T>target(java.lang.Class<T>,java.lang.String,T) in feign.hystrix.HystrixFeign.Builder and method <T>target(java.lang.Class<T>,java.lang.String,feign.hystrix.FallbackFactory<? extends T>) in feign.hystrix.HystrixFeign.Builder match

My Fallback definition is like below.

static class FallbackApiRetro implements PaymentRiskServiceFeignClient, FallbackFactory<FallbackApiRetro> {

It implements both my interface and the fallback factory. Is it the reason for this ambiguity? But the unit test, where I get the client instance works just fine.
I have the following dependencies and I made sure I don't have any other version of hystrix-core is getting pulled in.

       <feign.version>9.3.1</feign.version> 
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-gson</artifactId>
            <version>${feign.version}</version>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-core</artifactId>
            <version>${feign.version}</version>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-hystrix</artifactId>
            <version>${feign.version}</version>
        </dependency>

Is there anything jar i need to make sure to not to have in my classpath?

You'll need to cast it as a FallbackFactory to select the appropriate method since your class is both.

So taking the test case and start modifying it one by one helped me fix the issue. FallbackFactory is getting me the cause. Thank you @adriancole and @spencergibb

@seetharamani glad it worked out.

Was this page helpful?
0 / 5 - 0 ratings