Hi,

I'm using the version 3.0.1 of this library and I'm having problems with the fallback implementation. Seems it's not being triggered if any exception occurs.

I've configured a feign client with an invalid host as url in order to provoke an exception:

@FeignClient(name = "feignClientTest", url = "invalid.url", fallback = FeignClientTest.FallbackTest.class) public interface FeignClientTest {

@RequestMapping(method = RequestMethod.GET, value = "/fake/url")
String getFromFakeUrl();

@Component
class FallbackTest implements FeignClientTest {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    public String getFromFakeUrl() {
        log.debug("Fallback occurred for getFromFakeUrl");
        return "Fallback";
    }
}

}

After calling getFromFakeUrl() method, I get a java.net.UnknownHostException instead of the "Fallback" string used in the fallback implementation.

I set feign.circuitbreaker.enabled=true in application configuration file.

Should I configure anything more? Am I missing something?

Thanks in advance.

Comment From: cbezmen

Hi @pabloriesgo,

Please read Documentation. You implement FallbackFactory<FeignClientTest> instead of FeignClientTest.

So your fallback class look like:

@Component
class FallbackTest implements FallbackFactory<FeignClientTest> {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    public FeignClientTest create(Throwable cause) {
       return new FeignClientTest(){
             @Override
             public String getFromFakeUrl() {
                   log.debug("Fallback occurred for getFromFakeUrl");
                   return "Fallback";
             }
        }
    }
}

Comment From: pabloriesgo

Hi @cbezmen ,

Thanks for your quick response but I'm not using fallbackFactory, I'm using the fallback attribute:

@FeignClient(name = "feignClientTest", url = "invalid.url", fallback = FeignClientTest.FallbackTest.class)

I've also tried using fallbackFactory and defining it as you say and it didn't work either.

Comment From: cbezmen

hi @pabloriesgo ,

Are you define your FallbackTest class in FeignClientTest? Maybe you should move it to another class or try to add static field as mentioned in documentation

Comment From: pabloriesgo

Hi @cbezmen , Yes I also tried this way you mention:

@FeignClient(name = "feignClientTest", url = "invalid.url", fallback = FallbackTest.class) public interface FeignClientTest {

@RequestMapping(method = RequestMethod.GET, value = "/fake/url")
String getFromFakeUrl();

}

@Component public class FallbackTest implements FeignClientTest {

private final Logger log = LoggerFactory.getLogger(this.getClass());

@Override
public String getFromFakeUrl() {
    log.debug("Fallback occurred for getFromFakeUrl");
    return "Fallback";
}

}

But it didn't work either.

Comment From: cbezmen

Hi @pabloriesgo

I added example code to you and its working. You can move FeignClientTest and FallbackTest to a new class. It also works.

Example Code:

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@SpringBootApplication
@Slf4j
public class FallbackApplication {

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

    @Autowired
    private FeignClientTest feignClientTest;

    @Bean
    public ApplicationRunner test() {
        return args -> {
            String fromFakeUrl = feignClientTest.getFromFakeUrl();
            log.info("{}", fromFakeUrl);
        };
    }

    @FeignClient(name = "feignClientTest", url = "invalid.url", fallback = FallbackTest.class)
    public interface FeignClientTest {

        @RequestMapping(method = RequestMethod.GET, value = "/fake/url")
        String getFromFakeUrl();
    }

    @Component
    public class FallbackTest implements FeignClientTest {

        @Override
        public String getFromFakeUrl() {
            log.debug("Fallback occurred for getFromFakeUrl");
            return "Fallback";
        }
    }
}


Example Output: fallback_response

Comment From: pabloriesgo

Hi @cbezmen ,

Thanks for your response and example.

I've just found out seeing your example that it was not working because of the @EnableFeignClients I had in my spring boot application class, after removing it, it works.

I thought it was a required annotation. It's not needed anymore to enable feign clients?

To be honest, I'm a bit confused because in other applications I have, I need the @EnableFeignClients annotation in order to spring can find and inject classes annotated with @FeignClient annotation.

What is more, if I remove the fallback attribute and implementation in your example, the application does not start because it does not find any instance of FeignClientTest, because I think you have to add @EnableFeignClients for it.

Comment From: OlgaMaciaszek

@cbezmen Thanks a lot for triaging this and proposing a valid solution. @pabloriesgo @EnableFeignClients annotation most definitely works. You can see this working sample that uses it. However, please keep in mind this note from the docs:

To use @EnableFeignClients annotation on @Configuration-annotated-classes, make sure to specify where the clients are located, for example: @EnableFeignClients(basePackages = "com.example.clients") or list them explicitly: @EnableFeignClients(clients = InventoryServiceFeignClient.class)

Please take a look at the docs. Please let us know if you need any more help.

Comment From: pabloriesgo

Hi @OlgaMaciaszek ,

Thank you very much for your response.

There is still something I don't understand. If I add in @cbezmen example this:

@EnableFeignClients(clients = FallbackApplication.FeignClientTest.class)

The fallback is not triggered any more.

Comment From: pabloriesgo

Hi again,

I think I found the issue, after adding the maven dependency with spring-cloud-starter-netflix-hystrix, it began to work. I thought this library was not needed any more.

Thank you very much for your help.

Comment From: Aiernory

@cbezmen the fallback class whether be regarded as a @service class directly ?

I added example code to you and its working. You can move FeignClientTest and FallbackTest to a new class. It also works.

Example Code:

java ............. @SpringBootApplication @Slf4j public class FallbackApplication { .................... @Component public class FallbackTest implements FeignClientTest { @Override public String getFromFakeUrl() { log.debug("Fallback occurred for getFromFakeUrl"); return "Fallback"; } } }

Example Output: fallback_response

Comment From: cbezmen

Yes of course it also works out of the same class. I only share example code to help @pabloriesgo

Comment From: Aiernory

When no @EnableFeignClients , the fallback class is just a normal @service class. If add @EnableFeignClients , the fallback is not triggered.

And @pabloriesgo mention the maven dependency with spring-cloud-starter-netflix-hystrix , but the newest spring cloud had abandoned hystrix ....

and my using version is spring cloud 2020.0.4, generate by start.spring.io

Comment From: pabloriesgo

Hi @Aiernory ,

If it helps you, it only worked for me after adding the dependency with spring-cloud-starter-netflix-hystrix. I thought this dependency was not needed any more.

Best regards

Comment From: OlgaMaciaszek

You do need to provide an implementation library for Spring Cloud CircuitBreaker, which is just an abstraction over various implementations. Hystrix is, in fact, no longer supported. We recommend using Resillience4J instead. Please read Spring Cloud CircuitBreaker's documentation. If you come across more issues related to Spring Cloud CircuitBreaker itself and not with its OpenFeign integration, please open a separate issue in Spring Cloud CircuitBreaker repo.