编程基本原则-重试

98 阅读2分钟

定义

重试技术是在发生故障或异常情况时,自动尝试重新执行操作的一种技术。常见于各种异常情况,例如网络故障、服务端错误、资源不足等。

在实际应用中,重试技术通常需要设置一些参数,例如重试次数、重试间隔时间等,以根据具体的应用场景进行配置,从而最大程度地提高应用程序的可靠性和性能

优势

  • 提高程序的可靠性:当请求失败时,重试技术可以自动重新尝试请求,从而提高应用程序的可靠性。
  • 提高用户体验:重试技术可以让用户增加获取所需数据的成功率,提高用户的满意度。

案例

Axios-retry

Axios的retryretryDelay是通过使用axios-retry这个库来实现的。这个库会在Axios的请求拦截器中注册一个retry拦截器,并且在请求失败时触发拦截器的逻辑来进行重试。

源码地址

// 源码
export default function axiosRetry(axios, defaultOptions) {
  ...
  axios.interceptors.response.use(null, async (error) => {
    const { config } = error;

    // If we have no information to retry the request
    if (!config) {
      return Promise.reject(error);
    }

    const {
      retries = 3,
      retryCondition = isNetworkOrIdempotentRequestError,
      retryDelay = noDelay,
      shouldResetTimeout = false,
      onRetry = () => {}
    } = getRequestOptions(config, defaultOptions);

    const currentState = getCurrentState(config);
    
    // 
    if (await shouldRetry(retries, retryCondition, currentState, error)) {
      // 记录重试次数
      currentState.retryCount += 1;
      const delay = retryDelay(currentState.retryCount, error);

      ...
      
      // 发起重试
      return new Promise((resolve) => setTimeout(() => resolve(axios(config)), delay));
    }

    return Promise.reject(error);
  });
}

Retry

retry 是一个轻量级的、纯JavaScript实现的重试工具。

针对重试又封装好了很多技术细节,例如自定义重试次数重试间隔时间重试条件

源码地址

// 源码
RetryOperation.prototype.attempt = function(fn, timeoutOps) {
  this._fn = fn;

  // 支持最大重试的时间
  if (timeoutOps) {
    if (timeoutOps.timeout) {
      this._operationTimeout = timeoutOps.timeout;
    }
    if (timeoutOps.cb) {
      this._operationTimeoutCb = timeoutOps.cb;
    }
  }

  var self = this;
  if (this._operationTimeoutCb) {
    this._timeout = setTimeout(function() {
      self._operationTimeoutCb();
    }, self._operationTimeout);
  }

  this._operationStart = new Date().getTime();
  // 重试
  this._fn(this._attempts);
};
...

示例

下面以 oss上传文件 为例的 DEMO。

有些重试使用的是递归的方式,这里借助 for 循环Promise,实现重试功能。

const OSS = require('ali-oss');

const client = new OSS({
  region: 'your-region',
  accessKeyId: 'your-accessKeyId',
  accessKeySecret: 'your-accessKeySecret',
  bucket: 'your-bucket',
});

async function uploadWithRetry(filePath, options = {}) {
  const defaultOptions = {
    retries: 3,
    retryDelay: 5000,
  };

  options = { ...defaultOptions, ...options };
 
  for (let i = 0; i < options.retries; i++) {
    try {
      const result = await client.put(path.basename(filePath), filePath);
      return result;
    } catch (error) {
      await new Promise(resolve => setTimeout(resolve, options.retryDelay));
    }
  }
  throw new Error(`Failed to upload file after ${options.retries} retries.`);
}

uploadWithRetry('/path/to/file.txt')
  .catch(error => console.log('Error:', error));

总结

重试 是一种在多种场景下提高程序可靠性鲁棒性的技术手段,其包括减少请求失败率提高程序的稳定性可靠性等优势。