Skip to content

Instantly share code, notes, and snippets.

@coodoo
Last active February 5, 2024 05:31
Show Gist options
  • Save coodoo/77369d18b1767e71ce11510b85c3fcc6 to your computer and use it in GitHub Desktop.
Save coodoo/77369d18b1767e71ce11510b85c3fcc6 to your computer and use it in GitHub Desktop.
替 fetch 加上 retry 與 timeout 功能
/*
# goal
- 在不修改 node-fetch 原始參數格式下新增兩功能
1. 新增 timeout 設定且逾時自動重試
2. 新增 retry 模式可指定重試次數
- 所有 config{} 皆有預設值因此使用上與原始 fetch() 相同
- 目地是能無痛 drop-in replace 取代原始版
# non-goal
- 改用 axios 或其它 fetch 套件
- 原因是既有 codebase 內已大量使用 node-fetch 並備有完整測試
- 此時更換套件風險太大故不為止
*/
async function fatch(url, options = {}, config = {}) {
if (config.retry_count === undefined) config.retry_count = 0
let {
retries = 1,
delay = 30 * 1000,
timeout = 3 * 60 * 1000,
retry_count,
} = config
const controller = new AbortController()
options.signal = controller.signal
const tout = setTimeout(() => {
console.log(`[fatch] 連線逾時`, timeout)
controller.abort()
}, timeout)
return fetch(url, options)
.then(async (resp) => {
clearTimeout(tout)
return resp
})
.catch(async (err) => {
clearTimeout(tout)
console.log(`\n[fatch] 炸掉`, {
url,
retry_count,
config,
ts: new Date().toLocaleString('en-US', {
timeZone: 'Asia/Taipei',
hour12: false,
}),
err: err.message,
})
if (++config.retry_count <= retries) {
const time = config.retry_count * delay || 30 * 1000
console.log(`[fatch] 重試等待時間`, `${time}ms`)
await exports.wait(time)
console.log(`[fatch] 啟動重試次數`, config.retry_count)
return fatch(url, options, config)
} else {
const msg = `fatch 重試 ${config.retry_count - 1} 次皆失敗,只好放棄`
const cause = {
url,
config,
err,
}
throw new Error(msg, { cause })
}
})
}
exports.wait = (ms = 0) => new Promise((resolve) => setTimeout(resolve, ms))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment