Branko
Branko

Reputation: 91

Hystrix fallback method not called if Feign Client manually created with Feign.Builder

I am trying to create a Feign client that has a fallback method in case of failure.

By following examples i created a simple Feign Client:

@Component
@FeignClient(value = "authenticationClient", fallback = AuthenticationClientFallback.class)
public interface AuthenticationClient
{
@RequestMapping(method = RequestMethod.GET, value = "/auth/userinfo")
UserInfoResource getUserInfo(@RequestHeader("Authorization") String token);

@RequestMapping(method = RequestMethod.GET, value = "/auth/token")
TokenResource getToken(@RequestHeader("Authorization") String basicAuth);

}

The AuthenticaionClientFallback class is following:

 @Component
    public class AuthenticationClientFallback implements AuthenticationClient
    {
        public static final String NO_TOKEN = "No Token";

        @Override
        public UserInfoResource getUserInfo(String token)
        {
            return null;
        }

        @Override
        public TokenResource getToken(String basicAuth)
        {
            return new TokenResource(NO_TOKEN);
        } 
}

When i use my client with the @Autowire annotation, the fallback gets triggered. But i have a need to create my own feign client instance so i can dynamically set the URL.

Initialization of the AuthenticationClient:

public AuthenticationClient getAuthenticationClient()
    {
        return HystrixFeign.builder().contract(new SpringMvcContract())
                 .encoder(new JacksonEncoder())
                 .decoder(new JacksonDecoder())
                 .client(new OkHttpClient())
                 .logger(new Slf4jLogger(AuthenticationClient.class))
                 .logLevel(Logger.Level.FULL).target(AuthenticationClient.class, getTargetURL());
    }

And now my fallback methods never get called, just a FeignException is thrown with a message that a 401 status code is returned.

PS i have set feign.hystrix.enabled=true in .yml file and @EnableCircuitBreaker on app level.

Upvotes: 2

Views: 1993

Answers (1)

Dileepa Jayakody
Dileepa Jayakody

Reputation: 555

I think you have mixed the 2 feign client initialization methods; the declarative and manual initializations. You need to stick to one method.

If you are using the declarative initialization; you can use the @FeignClient annotation with the fallback like below;

@FeignClient(value = "authenticationClient", url = "${feign.url}", fallback = AuthenticationClientFallback.class)
public interface AuthenticationClient

And you can autowire the feign client in your components like this.

@Autowired
AuthenticationClient client;

If you are using the manual initialization of feign clients with some customizations; then you don't have to use @FeignClient annotation on AuthenticationClient class. You can create your customized feign clients like below;

@Autowired
AuthenticationClientFallback fallbackClient;

public AuthenticationClient getAuthenticationClient()
    {
        return HystrixFeign.builder().contract(new SpringMvcContract())
                 .encoder(new JacksonEncoder())
                 .decoder(new JacksonDecoder())
                 .client(new OkHttpClient())
                 .logger(new Slf4jLogger(AuthenticationClient.class))
                 .logLevel(Logger.Level.FULL).target(AuthenticationClient.class, getTargetURL(), fallbackClient);
    }

Please note that the fallbackClient object is passed in the .target() as an argument.

For more details refer the Spring cloud feign documentation

Upvotes: 1

Related Questions