重试,让程序更健壮

任何通过网络与其它应用通讯地的程序,都应该有足够的灵活性,来应对短暂的临时性故障。因为这些故障很多时候是可以自恢复的。

例如,为了避免服务过载,很多应用会采取某些限流措施,在并发请求达到一定数量时,暂时性的拒绝新的请求加入。这种情况下,尝试使用该应用的程序,一开始可能会被拒绝连接,但下一刻就好了。

因此,在设计系统时,应该考虑到此种故障。并且在条件允许时,加入重试机制,自动再次发起相应的请求。在某些情况下,可能会显著的改善应用程序的用户体验。

重试,让程序更健壮

能否发起重试,最重要的前提之一是,对同一资源的发起多次相同的请求,能否得到相同的结果。即资源接口是否具有幂等性。

标准 REST API 中,GET/HEAD/OPTIONS 通常是不会更改服务器上的资源的,因此大多是可重试的。

换个说法就是,如果能够确定,下次请求有可能成功,那就可以尝试重试。否则的话,就不必浪费时间、精力以及系统资源了。

例如,在请求 HTTP 服务时,收到 503 或 408 这样的状态码,则重试可能会有效;但是如果收到了 401 或 403 之类的状态码,则简单的重试肯定不起作用。

确定了什么情况下发起重试后,还有另外一个问题值得考虑。即在什么时间、以什么样的频率发起重试。尽管可以,但通常并不会是请求失败后,立即发起重试,而是需要根据具体的场景,选择合适的重试
时机。

假如说我们请求失败的原因,是服务端请求过载。则立即发起重试,除了给服务端添乱外,不会有其它结果。严重情况下,可能会加剧服务器的负担,直到耗尽服务器资源。

为了避免上述问题,常见的做法是在重试之前增加一些延迟。但是如何增加这些延迟,又有多种策略,比较多使用的有两种:

  • 固定间隔。即每次请求失败后,都等待固定的时间后,再次发起下次重试请求;
  • 指数递增。即多次请求之间的延时,成倍增加;

如果失败是由服务端过载引起的,则后一种策略可能会更好。假如它的初始请求在 0ms 发出,则第二次请求在失败 200ms 后发出,第三次请求在失败 400ms 后发出,第四次在 800ms... 以此类推。这种分散的请求和重试机制,可能有助于减缓客户端及服务器的负载,提高我们最终获取到成功结果的机会。

但是假如所有的请求都从同一时刻发起,并按照同样的机制延时重试,则两种策略是一样的,并不会有所改进。这种情况下,可能需要加入一些随机因素。

扯的有点多,接下来搞些实际的,上一点儿代码。简单起见,这里演示一下在 JavaScript 中的实现,使用诸位都了解的 axios。Axios 提供了拦截器机制,用来处理通用的重试逻辑正合适。

const SLEEP_TIME = 200;
const RETRY_TIMES = 3;
const RETRY_STATUS = [408, 503, 504];

function getSleepTime(i = 0) {
  const wTime = Math.min(SLEEP_TIME * 2 ** i);
  return Math.random() * wTime;
}

async function fakeSleep(ms) {
  await new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, ms);
  });
}

async function onError(error) {
  const { status } = error.response;
  let { retryCount = 0 } = error.response.config;

  if (RETRY_STATUS.includes(status) && retryCount < RETRY_TIMES) {
    retryCount += 1;
    sleep_ms = getSleepTime(retryCount);
    await fakeSleep(sleep_ms);

    error.config.retryCount = retryCount;
    return await axios(error.config);
  }
}

axios.interceptors.response.use(onError);

代码不多,应该不需要额外的解释。其它编程语言,实现思路大致也差不多。相信您肯定可以写出更好的。

欢迎批评指正。

作者:袁首京

原创文章,转载时请保留此声明,并给出原文连接。

原文链接:https://www.cnblogs.com/rockety/p/17306156.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:重试,让程序更健壮 - Python技术站

(0)
上一篇 2023年4月17日
下一篇 2023年4月17日

相关文章

  • js查看一个函数的执行时间实例代码

    首先,我们可以通过Date对象来获取时间戳,在函数执行前和执行后分别获取时间戳,然后计算时间戳的差值即可得到函数执行时间。 具体操作可以参考下列示例代码: function test() { // 获取函数执行前的时间戳 const startTime = new Date().getTime(); // 模拟函数执行 for (let i = 0; i &…

    JavaScript 2023年5月27日
    00
  • Javascript下判断是否为闰年的Datetime包

    要判断一个年份是否为闰年,一般需要满足以下两个条件中的一个或者同时满足: 年份能被4整除,但不能被100整除。 年份能被400整除。 我们可以使用JavaScript中的Datetime库的相关API实现闰年的判断。 首先,我们需要安装datetime包。在命令行中执行以下命令: npm install datetime 接下来,我们来演示两个不同的Java…

    JavaScript 2023年5月27日
    00
  • javascript中xml操作实现代码

    下面是关于JavaScript中XML操作实现代码的完整攻略。 XML简介 XML是一种被广泛用于Web应用程序中的标记式语言,用于存储和传输数据。XML有很多好处,包括易于阅读和理解,易于自定义,可扩展性强等。 基础知识 在JavaScript中,我们可以使用XMLDOM对象处理XML文档。XMLDOM是一个跨平台的API,可用于处理XML文档。XMLDO…

    JavaScript 2023年5月27日
    00
  • JavaScript异步加载浅析

    JavaScript 异步加载浅析 在网页开发中,我们经常会遇到需要加载外部资源(如CSS、JS等)的情况。传统的加载方式是同步加载,即在加载完一个资源后才会加载下一个资源,这样会导致页面加载速度较慢,影响用户体验。因此,异步加载成为了一个非常重要的技术。 异步加载是指在加载资源的同时,不会阻塞页面的其他操作,而是充分利用空闲时间进行资源加载。在 JavaS…

    JavaScript 2023年5月27日
    00
  • javascript动态加载实现方法一

    首先我们需要明确一下“javascript动态加载”是什么意思。 “javascript动态加载”指的是通过JavaScript在网页运行过程中动态加载(或移除)外部脚本或样式表等资源文件,而不是在HTML中直接使用<script>或<link>标签引用。 接下来我们来介绍一下“javascript动态加载实现方法一”的完整攻略,包括…

    JavaScript 2023年5月27日
    00
  • JavaScript 声明私有变量的两种方式

    下面是JavaScript声明私有变量的两种方式的完整攻略。 声明私有变量的两种方式 在JavaScript中,私有变量是指只能在类或对象内部访问的变量。通常情况下,我们用闭包或Symbol来实现私有变量的声明。 1. 闭包实现私有变量 闭包是指一个函数返回另一个函数,这个被返回的函数可以访问原函数的内部变量。下面来看一个闭包实现私有变量的示例: funct…

    JavaScript 2023年6月10日
    00
  • ES6 新增的创建数组的方法(小结)

    关于ES6新增的创建数组的方法,我可以给你提供一份完整的攻略。 概述 ES6新增了两种方式来创建数组,分别是“Array.from”和“Array.of”。 Array.from Array.from方法可以接收可迭代对象(比如集合和映射)或类数组对象(比如DOM节点列表)作为第一个参数,然后将其转换为一个新的数组并返回。 // 创建字符串为参数的集合 le…

    JavaScript 2023年5月27日
    00
  • JS前端知识点offset,scroll,client,冒泡,事件对象的应用整理总结

    下面我将详细讲解关于“JS前端知识点offset,scroll,client,冒泡,事件对象的应用整理总结”的攻略以及示例说明。 标题 一、offset、scroll、client的应用说明 1. offset offset是获取元素相对于其offsetParent的位置信息,包括元素的宽高、距离上下左右的距离。使用offsetLeft和offsetTop属…

    JavaScript 2023年6月11日
    00
合作推广
合作推广
分享本页
返回顶部