# 第4节.Nacos中优雅的重试请求代码

我们知道,在后端开发中,对于网络间的调用经常会采用代码重试机制去保证代码执行,对于一些经验尚浅的开发者来说,学习一些开源框架中优秀的请求代码重试机制的代码设计也是很有帮助的。

Nacos中的请求代码重试的代码设计思路也是对我们的开发很有帮助的。

这里以RpcClient类为例,他的主要代码如下:

package com.alibaba.nacos.common.remote.client;

public abstract class RpcClient implements Closeable {
		/**
		* 定义最大重试次数:3次
		*/
	  private static final int RETRY_TIMES = 3;
  
  	 /**
     * 发送请求
     */
    public Response request(Request request, long timeoutMills) throws NacosException {
        int retryTimes = 0;
        Response response;
        Exception exceptionThrow = null;
      	//定义当前请求的开始时间
        long start = System.currentTimeMillis();
      	//如果当前重试次数 小于 默认重试次数  并且  当前时间戳小于未来的超时时间戳
        while (retryTimes < RETRY_TIMES && System.currentTimeMillis() < timeoutMills + start) {
            boolean waitReconnect = false;
            try {
              	//检查客户端是否处于连接状态
                if (this.currentConnection == null || !isRunning()) {
                    waitReconnect = true;
                    throw new NacosException(NacosException.CLIENT_DISCONNECT,
                            "Client not connected, current status:" + rpcClientStatus.get());
                }
                response = this.currentConnection.request(request, timeoutMills);
             		// 省略一部分代码
              	//............
              	// 省略一部分代码
                // return response.
								//更新最后时间戳,并返回响应
                lastActiveTimeStamp = System.currentTimeMillis();
                return response;
                
            } catch (Exception e) {
                if (waitReconnect) {
                    try {
                        // wait client to reconnect.
                        Thread.sleep(Math.min(100, timeoutMills / 3));
                    } catch (Exception exception) {
                        // Do nothing.
                    }
                }
                
                exceptionThrow = e;
                
            }
          	//走到这里说明请求失败了,重试次数+1
            retryTimes++;
            
        }
        //CAS 对象标记为不健康
        if (rpcClientStatus.compareAndSet(RpcClientStatus.RUNNING, RpcClientStatus.UNHEALTHY)) {
            switchServerAsyncOnRequestFail();
        }
        //如果存在请求处理异常错误信息
        if (exceptionThrow != null) {
            throw (exceptionThrow instanceof NacosException) ? (NacosException) exceptionThrow
                    : new NacosException(SERVER_ERROR, exceptionThrow);
        } else {
            throw new NacosException(SERVER_ERROR, "Request fail, unknown Error");
        }
    }
}

可以看到,这个是一个很经典的请求重试的代码设计模板,对于日常开发中自己的业务中需要请求重试的时候,也可以参考这个代码片段的设计实现。同样的代码设计实现,该类中的asyncRequest方法也可以进行参考。这个代码片段是先执行业务代码后,在进行重试次数的处理,如果某些情况需要先对次数进行处理,然后再进行业务代码,此时可以参考该类中的重试次数减法的代码设计。

int startUpRetryTimes = RETRY_TIMES;
while (startUpRetryTimes > 0 && connectToServer == null) {
    try {
        startUpRetryTimes--;
        ServerInfo serverInfo = nextRpcServer();
        
        LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Try to connect to server on start up, server: {}", name,
                serverInfo);
        
        connectToServer = connectToServer(serverInfo);
    } catch (Throwable e) {
        LoggerUtils.printIfWarnEnabled(LOGGER,
                "[{}] Fail to connect to server on start up, error message = {}, start up retry times left: {}",
                name, e.getMessage(), startUpRetryTimes);
    }
    
}

这段代码其实是Nacos中Grpc进行服务检查的核心代码,通过重试3次的处理,每一次轮训机器中的列表进行网络请求检查。

Last Updated: 7/10/2022, 1:50:01 PM