如果受 hystrix 保护的调用超时,我可以抛出自定义错误吗?
Can I throw a custom error if a hystrix-protected call times out?
我有一个伪造的客户端与这个外部调用:
@RequestMapping(method = RequestMethod.GET, value = "GetResourceA", consumes = "application/json")
@Cacheable("ResourceA")
List<Stop> getResourceA() throws MyOwnException;
在我的 application.yml
中我有这个设置:
hystrix:
command:
default:
execution.isolation.thread.timeoutInMilliseconds: 1000
fallback.enabled: false
现在,如果 getResourceA 超时,即需要超过一秒的时间才能完成,我要么得到这个:
com.netflix.hystrix.exception.HystrixRuntimeException: getResourceA timed-out and no fallback available
或者,如果我定义了一个我抛出我自己的异常的回退,我得到这个:
com.netflix.hystrix.exception.HystrixRuntimeException: getResourceA timed-out and fallback failed.
我可以不从回退中抛出自己的异常吗?
如果我想在服务停止时抛出我自己的异常怎么办?我不想有回退(因为我没有从回退到 return 的合理价值),而是抛出我自己可以捕获并让程序恢复的错误。有人可以帮我解决这个问题吗?
Ben回答后更新:
所以我尝试了捕获 HysterixRuntimeException 并检查导致它的原因的方法,但最终得到了这个丑陋的代码:
try {
getResourceA();
} catch (HystrixRuntimeException e) {
if (e.getFailureType().name().equals("TIMEOUT")) {
throw new MyOwnException("Service timed out");
}
throw e;
}
所有这些都能够在超时时抛出 MyOwnException。肯定还有别的办法吧?
您应该能够通过获取 HystrixRuntimeException
的原因来获取从后备中抛出的异常
因此,要处理您的自定义异常,您可以这样做:
try {
getResourceA();
} catch (HystrixRuntimeException e) {
if (e.getCause() instanceof MyException) {
handleException((MyException)e.getCause());
}
}
您可以从那里使用 ErrorDecoder 和 return 您自己的异常,然后使用异常处理程序。我遇到了类似的问题并这样解决了:
public class ExceptionHandlerControllerAdvice extends ResponseEntityExceptionHandler
...
@ResponseStatus(BAD_REQUEST)
@ExceptionHandler(HystrixRuntimeException.class)
public ExceptionResponse handleHystrixRuntimeException(HystrixRuntimeException exception) {
if(exception.getCause() instanceof MyException) {
return handleMyException((MyException) exception.getCause());
...
然后在我的 FeignClient 配置 class 中:
@Bean
public ErrorDecoder feignErrorDecoder() {
return new ErrorDecoder() {
@Override
public Exception decode(String methodKey, Response response) {
return new MyException("timeout");
}
};
}
这样你就不需要多个嵌套的 getCause()
如果想替换hystrix抛出的超时异常,可以这样写:
try {
testClient.timeoutTest();
} catch (HystrixRuntimeException e) {
Throwable fallbackException = e.getFallbackException();
if (fallbackException.getCause().getCause() instanceof CustomException) {
log.info("customer exception!");
}
}
我有一个伪造的客户端与这个外部调用:
@RequestMapping(method = RequestMethod.GET, value = "GetResourceA", consumes = "application/json")
@Cacheable("ResourceA")
List<Stop> getResourceA() throws MyOwnException;
在我的 application.yml
中我有这个设置:
hystrix:
command:
default:
execution.isolation.thread.timeoutInMilliseconds: 1000
fallback.enabled: false
现在,如果 getResourceA 超时,即需要超过一秒的时间才能完成,我要么得到这个:
com.netflix.hystrix.exception.HystrixRuntimeException: getResourceA timed-out and no fallback available
或者,如果我定义了一个我抛出我自己的异常的回退,我得到这个:
com.netflix.hystrix.exception.HystrixRuntimeException: getResourceA timed-out and fallback failed.
我可以不从回退中抛出自己的异常吗?
如果我想在服务停止时抛出我自己的异常怎么办?我不想有回退(因为我没有从回退到 return 的合理价值),而是抛出我自己可以捕获并让程序恢复的错误。有人可以帮我解决这个问题吗?
Ben回答后更新:
所以我尝试了捕获 HysterixRuntimeException 并检查导致它的原因的方法,但最终得到了这个丑陋的代码:
try {
getResourceA();
} catch (HystrixRuntimeException e) {
if (e.getFailureType().name().equals("TIMEOUT")) {
throw new MyOwnException("Service timed out");
}
throw e;
}
所有这些都能够在超时时抛出 MyOwnException。肯定还有别的办法吧?
您应该能够通过获取 HystrixRuntimeException
因此,要处理您的自定义异常,您可以这样做:
try {
getResourceA();
} catch (HystrixRuntimeException e) {
if (e.getCause() instanceof MyException) {
handleException((MyException)e.getCause());
}
}
您可以从那里使用 ErrorDecoder 和 return 您自己的异常,然后使用异常处理程序。我遇到了类似的问题并这样解决了:
public class ExceptionHandlerControllerAdvice extends ResponseEntityExceptionHandler
...
@ResponseStatus(BAD_REQUEST)
@ExceptionHandler(HystrixRuntimeException.class)
public ExceptionResponse handleHystrixRuntimeException(HystrixRuntimeException exception) {
if(exception.getCause() instanceof MyException) {
return handleMyException((MyException) exception.getCause());
...
然后在我的 FeignClient 配置 class 中:
@Bean
public ErrorDecoder feignErrorDecoder() {
return new ErrorDecoder() {
@Override
public Exception decode(String methodKey, Response response) {
return new MyException("timeout");
}
};
}
这样你就不需要多个嵌套的 getCause()
如果想替换hystrix抛出的超时异常,可以这样写:
try {
testClient.timeoutTest();
} catch (HystrixRuntimeException e) {
Throwable fallbackException = e.getFallbackException();
if (fallbackException.getCause().getCause() instanceof CustomException) {
log.info("customer exception!");
}
}