Search code examples
spring-cloudhystrixcircuit-breaker

strange behavior of HystrixCommand


The project uses SpringBoot(2.3.4) and SpringCloud(Hoxton.SR8).
There are three classes: BillController, BillService(interface) and BillServiceImpl (implements BillService), BillController calls function getBillList declared in BillService.

In BillServiceImpl, there are two method, one is getBillList, the other is simulateUnstableService, getBillList calls simulateUnstableService, and in simulateUnstableService just a long sleep(2000).

The strange thing is that if I annoate getBillList with HystrixCommand, then it works as I expect. But if I move HystrixCommand to annoate simulateUnstableService, then there is no break which means timeout does not trigger Circuit Breaker.

@Service
public class BillServiceImpl implements BillService {

    @Override
    // have effact
    @HystrixCommand(
            commandProperties = {
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
            }
    )
    public List<Bill> getBillList(long userId) {
        return simulateUnstableService(userId);
    }

// no effact
//    @HystrixCommand(
//            commandProperties = {
//                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
//            }
//    )
    public List<Bill> simulateUnstableService(long userId) {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return new ArrayList<>();
    }
}

And more, if I just copy simulateUnstableService method content to getBillList, and annoate getBillList with HystrixCommand, the breaker also works.
Why?


Solution

  • Excellent question.

    Hystrix uses AOP to wrap the method being called and deliver the Circuit Braking functionality. There is actually an aspect class HystrixCommandAspect.java which defines the around advice used to achieve this.

    Now, AOPs don't exactly work if you call a method from within a class. See this answer for more clarity- Spring AOP not working for method call inside another method