NodeJS实现Retry重试策略和回退尝试

需求描述

在服务端经常会遇到异常故障,对于重要业务我们会对异常进行捕获,并进行重试或回退尝试。

例如,短信服务。当我们调用第三方的短信服务由于网络超时,导致调用API失败无法给用户下发验证码。通常,我们会使用 try...catch 捕获异常,并执行一次补发。但是可能由于网络异常再次失败。那么,如何实现多次重试策略呢。

实现 retry 的核心思想是, 递归调用

* @param {number} retries - 重试次数 * @param {Function} fn - 重试函数 const retry = (retries, fn) => { fn().catch((err) => retries > 1 ? retry(retries - 1, fn) : Promise.reject(err));

增强版 - 增加延迟重试

// 首先实现一个暂停函数
const pause = (duration) => new Promise((reslove) => setTimeout(reslove, duration));
const backoff = (retries, fn, delay = 500) => {
  fn().catch((err) => retries>1
    ? pause(delay).then(() => backoff(retries-1, fn, delay))
    : Promise.reject(err)

在实现pause函数时,始终不明白后半部分代码的含义,为什么setTimeout(reslove, duration)可以直接传一个reslove
后来才想明白,setTimeout第一个参数是需要延迟执行的函数,而reslove本身就是一个函数。

最后,附上 setTimeoutAPI文档

*   `callback` 当定时器到点时要调用的函数。
*   `delay`  调用 `callback` 之前要等待的毫秒数。
*   `...args` 当调用 `callback` 时要传入的可选参数
setTimeout(callback, delay[, ...args])
预定在 `delay` 毫秒之后执行的单次 `callback`。 返回一个用于 [`clearTimeout()`](http://nodejs.cn/s/L4L2Xr) 的 `Timeout`。
`callback` 可能不会精确地在 `delay` 毫秒被调用。 Node.js 不能保证回调被触发的确切时间,也不能保证它们的顺序。 回调会在尽可能接近所指定的时间上调用。
注意:当 `delay` 大于 `2147483647` 或小于 `1` 时,`delay` 会被设为 `1`。
如果 `callback` 不是一个函数,则抛出 [`TypeError`](http://nodejs.cn/s/Z7Lqyj)