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本身就是一个函数。

最后,附上 setTimeout的API文档

*   `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)


参考资料

  • https://tech.mybuilder.com/handling-retries-and-back-off-attempts-with-javascript-promises/
  • NodeJS async/await with retry
  • Retry优雅的失败重试策略
  • Automatically retry an async await function n times

你可能感兴趣的:(NodeJS实现Retry重试策略和回退尝试)