I write a hystrix like this:
`public class HystrixCommandAdvice {
public Object runCommand(final ProceedingJoinPoint pjp) {
return wrapWithHystrixCommnad(pjp).execute();
}
private HystrixCommand<Object> wrapWithHystrixCommnad(final ProceedingJoinPoint pjp) {
return new HystrixCommand<Object>(setter()) {
@Override
protected Object run() throws Exception {
try {
return pjp.proceed();
} catch (Throwable throwable) {
throw (Exception) throwable;
}
}
@Override
protected Object getFallback() {
Map<String,Object> map = new HashMap<String,Object>();
map.put("msg", "system is wrong");
if(this.isCircuitBreakerOpen()){
logger.info("----------Hystrix circuit breaker Open!----");
map.put("circuit breaker", "consume circuite breaker is open");
}else{
logger.info("----------Hystrix circuit breaker Close!----");
}
logger.info("------------Hystrix fallback!----------------");
return map;
}
};
}
private HystrixCommand.Setter setter() {
return HystrixCommand.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupName))
.andCommandKey(HystrixCommandKey.Factory.asKey(commandName))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withCircuitBreakerEnabled(Boolean.parseBoolean(withCircuitBreakerEnabled))
.withCircuitBreakerForceClosed(Boolean.parseBoolean(withCircuitBreakerForceClosed))
.withCircuitBreakerForceOpen(Boolean.parseBoolean(withCircuitBreakerForceOpen))
.withCircuitBreakerErrorThresholdPercentage(Integer.parseInt(withCircuitBreakerErrorThresholdPercentage))
.withCircuitBreakerRequestVolumeThreshold(Integer.parseInt(withCircuitBreakerRequestVolumeThreshold))
.withCircuitBreakerSleepWindowInMilliseconds(Integer.parseInt(withCircuitBreakerSleepWindowInMilliseconds)));
}
}
`
and configure it with the following configuration in the applicationContext.xml:
`
<property name="withCircuitBreakerEnabled" value="true"></property>
<property name="withCircuitBreakerForceClosed" value ="false"></property>
<property name="withCircuitBreakerForceOpen" value ="false"></property>
<property name="withCircuitBreakerErrorThresholdPercentage" value ="50"></property>
<property name="withCircuitBreakerRequestVolumeThreshold" value ="10"></property>
<property name="withCircuitBreakerSleepWindowInMilliseconds" value ="20000"></property>
</bean>
<aop:config>
<aop:aspect id="consumeServiceAspect" ref="consumeCommand">
<aop:pointcut id="consumeServiceTarget"
expression="execution(* com.mobile.pay.service.impl.PayUserConsumeServiceImpl.consume(..))"/>
<aop:around method="runCommand" pointcut-ref="consumeServiceTarget"/>
</aop:aspect>
</aop:config> `
and the target method is annotationed with @Transactional :
`@Override
@Transactional(propagation=Propagation.REQUIRED)
public Map
//some CUD operation
}`
when there is a SQL Exception, the hystrix works well,however, there is no rolling back. It means that the hystrix intercepts the Exception before the Spring transaction?
I add the following code
@Override
@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)
then the hystrix and transaction work well.
I guess that the hystrix intercept the exception and transform this exception to another exception which the spring transaction can not roll back for it.
If Spring is wrapping Hystrix, then it will only get what a normal caller of Hystrix would get. In the case of a fallback, that would generally be either the normal value, or the fallback value, not an exception at all.
You mean that the hystrix will intercept the exception and it would not throw it to the spring?
I override the run method as follow:
@Override
protected Object run() throws Exception {
try {
return pjp.proceed();
} catch (Throwable throwable) {
throw (Exception) throwable;
}
}
It will throw the exception, however, the spring cannnot notice it. I guess the reason is the forked thread will not throw the exception to the main thread. @mattrjacobs
@jordandandan
Spring @Transactional will only rollback RuntimeException by default. SQLException is a checked Exception. That is why you add rollbackFor=Exception.class then rollback works.
Looks answered now. Thanks @yanglifan ! Please re-open if there's more to discuss
Most helpful comment
@jordandandan
Spring
@Transactionalwill only rollbackRuntimeExceptionby default.SQLExceptionis a checked Exception. That is why you addrollbackFor=Exception.classthen rollback works.