以下文章来源于IT人的职场进阶 ,作者骆俊武
前亚马逊工程师,现大厂技术管理者。程序人生很长,我将我所经历的,有感而发的,呈现在这里。
(给ImportNew加星标,提高Java技能)
作者:骆俊武
public class TimeoutFilter implements Filter {
public TimeoutFilter() {
}
public Result invoke(...) throws RpcException {// 执行真正的逻辑调用,并统计耗时
long start = System.currentTimeMillis();
Result result = invoker.invoke(invocation);
long elapsed = System.currentTimeMillis() - start;
// 判断是否超时
if (invoker.getUrl() != null && elapsed > timeout) {// 打印warn日志
logger.warn("invoke time out...");
}
return result;
}
}public class TimeoutFilter implements Filter
public class FailoverClusterInvoker {
public Result doInvoke(...) {
...
// 循环调用设定的重试次数
for (int i = 0; i < retryTimes; ++i) {
...
try {
Result result = invoker.invoke(invocation);
return result;
} catch (RpcException e) {
// 如果是业务异常,终止重试
if (e.isBiz()) {
throw e;
}
le = e;
} catch (Throwable e) {
le = new RpcException(...);
} finally {
...
}
}
throw new RpcException("...");
}
}FailoverCluster是集群容错的缺省模式,当调用失败后会切换成调用其他服务器。再看下doInvoke方法,当调用失败时,会先判断是否是业务异常,如果是则终止重试,否则会一直重试直到达到重试次数。
继续跟踪invoker的invoke方法,可以看到在请求发出后通过Future的get方法获取结果,源码如下:
public Object get(int timeout) {
if (timeout <= 0) {
timeout = 1000;
}
if (!isDone()) {
long start = System.currentTimeMillis();
this.lock.lock();
try {
// 循环判断
while(!isDone()) {
// 放弃锁,进入等待状态
done.await((long)timeout, TimeUnit.MILLISECONDS);
// 判断是否已经返回结果或者已经超时
long elapsed = System.currentTimeMillis() - start;
if (isDone() || elapsed > (long)timeout) {
break;
}
}
} catch (InterruptedException var8) {
throw new RuntimeException(var8);
} finally {
this.lock.unlock();
}
if (!isDone()) {
// 如果未返回结果,则抛出超时异常
throw new TimeoutException(...);
}
}
return returnFromResponse();
}进入方法后开始计时,如果在设定的超时时间内没有获得返回结果,则抛出TimeoutException。因此,消费端的超时逻辑同时受到超时时间和超时次数两个参数的控制,像网络异常、响应超时等都会一直重试,直到达到重试次数。
看完本文有收获?请转发分享给更多人
关注「ImportNew」,提升Java技能
好文章,我在看❤️