Search code examples
spring-bootnetflix-eurekahystrixspring-cloud-feignnetflix-ribbon

Testing Hystrix fallback through Feign API: com.netflix.client.ClientException: Load balancer does not have available server for client


When testing the Hystrix fallback behavior of my Feign API, I get an error, when I expect it to succeed.

Feign interface:

This is the api to the external service.

@FeignClient(name = "book", fallback = BookAPI.BookAPIFallback.class)
public interface BookAPI {

    @RequestMapping("/")
    Map<String, String> getBook();

    @Component
    class BookAPIFallback implements BookAPI {

        @Override
        @RequestMapping("/")
        public Map<String, String> getBook() {
            Map<String, String> fallbackmap = new HashMap<>();
            fallbackmap.put("book", "fallback book");
            return fallbackmap;
        }
    }

}

Test class

This test exists just to verify fallback behavior:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = NONE)
public class BookServiceClientTest {

    @MockBean
    RestTemplate restTemplate;// <---- @LoadBalanced bean

    @Autowired
    private BookServiceClient bookServiceClient;

    @Before
    public void setup() {
        when(restTemplate.getForObject(anyString(), any()))
                .thenThrow(new RuntimeException("created a mock failure"));
    }

    @Test
    public void fallbackTest() {
        assertThat(bookServiceClient.getBook())
                .isEqualTo(new BookAPI.BookAPIFallback().getBook().get("book")); // <--- I thought this should work
    }
}

config files

application.yml

These files show configuration that might be relevant:

feign:
  hystrix:
    enabled: true

test/application.yml

eureka:
  client:
    enabled: false

The Question

Everything works fine when running the apps.
But when running this test, I get the below error.
Naturally, it's a test, so I'm trying to bypass the lookup anyway.

java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: book

at org.springframework.cloud.netflix.feign.ribbon.LoadBalancerFeignClient.execute(LoadBalancerFeignClient.java:71)
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:97)

What am I missing?

Addendums

Application class

@SpringBootApplication
@EnableCircuitBreaker
@EnableDiscoveryClient
@EnableFeignClients
public class LibraryApplication {

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

}

LibraryController

@Controller
public class LibraryController {

    private final BookServiceClient bookService;

    public LibraryController(BookServiceClient bookServiceClient) {
        this.bookService = bookServiceClient;
    }

    @GetMapping("/")
    String getLibrary(Model model) {
        model.addAttribute("msg", "Welcome to the Library");
        model.addAttribute("book", bookService.getBook());
        return "library";
    }

}

There are no other classes.


Solution

  • so! I was able to recreate the issue, thanks for adding more code, had to play about with it a tad as I was unsure what the BookClientService looked like and it wouldn't make sense for it to implement the BookAPI as that would be an internal call e.g. in your application and not an external API call with Feign.

    Anyway,

    I pushed my version of what you provided here.

    https://github.com/Flaw101/feign-testing

    The issue was resolved when I renamed the second application.yml which lives in the src/test/resources folder to application-test.yml which will merge the properties.

    The issue was caused by the fact the second property source, the testing one, overrides the initial application.yml and disables hystrix, because Hystrix is disabled there is no fallback to go to and it throws the root cause of what would cause the fallback, a lack of a server to call to for the Book API. Renaming it to application-test will always be loaded into spring test contexts. You could resolve it with the use of inlined properties or profiles.

    I've added another test disabling feign /w hystrix within the test which re-creates the error you are recieving.