use of com.github.df.restypass.exception.execute.RestyException in project RestyPass by darren-fu.
the class RestyFuture method get.
@Override
public T get() throws RestyException {
Response response;
try {
response = future.get();
} catch (InterruptedException | ExecutionException e) {
future.abort(e);
log.warn("获取响应失败:{}", e.getMessage());
if (this.getRestyCommand().isAsyncArg() || this.getRestyCommand().isAsyncReturn()) {
throw new RestyException(e);
}
response = FailedResponse.create(new ConnectionException(e));
}
T resp = (T) ResponseConverterContext.DEFAULT.convertResponse(restyCommand, response);
if (restyCommand.isAsyncReturn() || restyCommand.isAsyncArg()) {
if (RestyCommandStatus.FAILED == restyCommand.getStatus() && restyCommand.getFailException() != null) {
throw restyCommand.getFailException();
}
}
return resp;
}
use of com.github.df.restypass.exception.execute.RestyException in project RestyPass by darren-fu.
the class RestyProxyInvokeHandler method invoke.
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (isSpecialMethod(method)) {
return handleSpecialMethod(proxy, method, args);
}
Object result;
// 创建请求载体,RestyCommand
RestyCommand restyCommand = new DefaultRestyCommand(method.getDeclaringClass(), method, method.getGenericReturnType(), args, restyCommandContext);
// 获取过滤器
List<CommandFilter> filterList = commandFilterContext.getFilterList();
// 执行过滤器
for (CommandFilter commandFilter : filterList) {
if (CommandFilterType.BEFOR_EXECUTE.equals(commandFilter.getFilterType()) && commandFilter.shouldFilter(restyCommand)) {
commandFilter.before(restyCommand);
}
}
// 创建负载均衡器
LoadBalancer loadBalancer = LoadBalanceFactory.createLoadBalancerForService(restyCommand.getServiceName(), restyCommand.getRestyCommandConfig().getLoadBalancer());
// 为executor设置服务容器
commandExecutor.setServerContext(serverContext);
try {
if (commandExecutor.executable(restyCommand)) {
result = commandExecutor.execute(loadBalancer, restyCommand);
} else {
throw new IllegalStateException("Resty command is not executable:" + restyCommand);
}
} catch (RestyException ex) {
if (fallbackExecutor.executable(restyCommand)) {
if (log.isDebugEnabled()) {
log.debug("{}使用降级服务", restyCommand.getPath());
}
try {
result = fallbackExecutor.execute(restyCommand);
} catch (FallbackException fe) {
log.warn("服务{}降级发生异常:{}", restyCommand.getPath(), fe.getMessage());
// 抛出原始Resty异常
throw ex;
}
} else {
log.warn("请求{}发生异常:{}", restyCommand.getPath(), ex.getMessage());
throw ex;
}
}
return result;
}
use of com.github.df.restypass.exception.execute.RestyException in project RestyPass by darren-fu.
the class RestyCommandExecutor method execute.
@Override
public Object execute(LoadBalancer lb, RestyCommand restyCommand) throws RestyException {
if (restyCommand.getRestyCommandConfig().isForceBreakEnabled()) {
throw new CircuitBreakException("circuit breaker is forced to open");
}
// 重试次数
int retry = restyCommand.getRestyCommandConfig().getRetry();
Object result = null;
CircuitBreaker circuitBreaker = CircuitBreakerFactory.createDefaultCircuitBreaker(restyCommand.getServiceName());
// RestyCommand ready to start
restyCommand.ready(circuitBreaker);
// 排除 彻底断路的server, 尝试过的server
// 1.判断command使用的serverInstanceList是否存在被熔断的server
// 1.1 存在的话 server加入 loadBalance 的excludeServerList
Set<String> excludeInstanceIdSet = circuitBreaker.getBrokenServer();
// 负载均衡器 选择可用服务实例
ServerInstance serverInstance = lb.choose(serverContext, restyCommand, excludeInstanceIdSet);
if (serverInstance == null) {
throw new RuntimeException("no instances found:" + restyCommand.getServiceName() + ":" + serverContext.getServerList(restyCommand.getServiceName()));
}
// 重试机制
for (int times = 0; times <= retry; times++) {
try {
boolean shouldPass = circuitBreaker.shouldPass(restyCommand, serverInstance);
if (!shouldPass) {
// fallback or exception
throw new CircuitBreakException("circuit breaker is open");
}
RestyFuture future = restyCommand.start(serverInstance);
RestyFuture futureArg = getFutureArg(restyCommand);
if (restyCommand.isAsyncArg()) {
// 直接返回null, 结果放入出参RestyFuture中
return null;
}
if (restyCommand.isAsyncReturn()) {
// 返回RestyFuture
return future;
}
// 同步调用
result = future.get();
if (restyCommand.getStatus() == RestyCommandStatus.FAILED) {
throw restyCommand.getFailException();
}
if (restyCommand.getStatus() == RestyCommandStatus.SUCCESS) {
// 响应成功,无需重试了
break;
}
} catch (Exception ex) {
if (times == retry) {
throw ex;
} else {
// 将本次使用的server 加入排除列表
if (excludeInstanceIdSet == null || excludeInstanceIdSet == Collections.EMPTY_SET) {
excludeInstanceIdSet = new HashSet<>();
}
if (serverInstance != null) {
excludeInstanceIdSet.add(serverInstance.getInstanceId());
}
// 选择server, 如果没有server可选则无需重试,直接抛出当前异常
serverInstance = lb.choose(serverContext, restyCommand, excludeInstanceIdSet);
if (serverInstance == null || excludeInstanceIdSet.contains(serverInstance.getInstanceId())) {
throw ex;
} else if (log.isDebugEnabled()) {
log.debug("请求切换服务实例重试:{}", serverInstance);
}
}
}
}
return result;
}
use of com.github.df.restypass.exception.execute.RestyException in project RestyPass by darren-fu.
the class RestyFuture method get.
@SuppressWarnings("NullableProblems")
@Override
public T get(long timeout, TimeUnit unit) throws RestyException {
Response response;
try {
response = future.get(timeout, unit);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
future.abort(e);
log.error("获取响应失败:{}", e.getMessage());
if (this.getRestyCommand().isAsyncArg() || this.getRestyCommand().isAsyncReturn()) {
throw new RestyException(e);
}
response = FailedResponse.create(new ConnectionException(e));
}
T resp = (T) ResponseConverterContext.DEFAULT.convertResponse(restyCommand, response);
if (restyCommand.isAsyncReturn() || restyCommand.isAsyncArg()) {
if (RestyCommandStatus.FAILED == restyCommand.getStatus() && restyCommand.getFailException() != null) {
throw restyCommand.getFailException();
}
}
return resp;
}
use of com.github.df.restypass.exception.execute.RestyException in project RestyPass by darren-fu.
the class ResponseConverterContext method convertResponse.
/**
* Convert response object.
*
* @param restyCommand the resty command
* @param response the response
* @return the object
*/
public Object convertResponse(RestyCommand restyCommand, Response response) {
Object result = null;
// response 为null
if (response == null) {
log.warn("response is null,command:{}", restyCommand);
restyCommand.failed(new ServerException("Failed to get response, it's null"));
return result;
}
// response为FailedResponse, [connectException InterruptedException] status 500
if (FailedResponse.isFailedResponse(response)) {
log.warn("response is failed by exception:{}", FailedResponse.class.cast(response).getException().getMessage(), FailedResponse.class.cast(response).getException());
restyCommand.failed(FailedResponse.class.cast(response).getException());
return result;
}
// 服务响应了请求,但是不是200
int statusCode = response.getStatusCode();
if (200 != statusCode) {
if (statusCode >= 400 && statusCode < 500) {
restyCommand.failed(new RequestException("Request: " + restyCommand + "; Response: " + response.toString()));
} else if (statusCode >= 500) {
restyCommand.failed(new ServerException("Request: " + restyCommand + "; Response: " + response.toString()));
}
log.warn("request is bad,status code:{},request:{},response:{}", statusCode, restyCommand, response);
return result;
}
byte[] body = response.getResponseBodyAsBytes();
// 使用转换器 转换响应结果 json->object
boolean converted = false;
Type returnType = restyCommand.getReturnType();
String respContentType = response.getContentType();
for (ResponseConverter converter : converterList) {
if (converter.support(returnType, respContentType)) {
converted = true;
result = converter.convert(body, returnType, respContentType);
break;
}
}
if (!converted) {
restyCommand.failed(new RestyException("没有合适的解析器,content-type:" + respContentType + ";body:" + response.getResponseBody()));
log.warn("没有合适的解析器,content-type:{};body:{}", respContentType, response.getResponseBody());
}
restyCommand.success();
return result;
}
Aggregations