get-it
Version:
Generic HTTP request library for node, browsers and workers
47 lines (37 loc) • 1.57 kB
text/typescript
import type {Middleware, RetryOptions} from 'get-it'
const isStream = (stream: any) =>
stream !== null && typeof stream === 'object' && typeof stream.pipe === 'function'
/** @public */
export default (opts: RetryOptions) => {
const maxRetries = opts.maxRetries || 5
const retryDelay = opts.retryDelay || getRetryDelay
const allowRetry = opts.shouldRetry
return {
onError: (err, context) => {
const options = context.options
const max = options.maxRetries || maxRetries
const delay = options.retryDelay || retryDelay
const shouldRetry = options.shouldRetry || allowRetry
const attemptNumber = options.attemptNumber || 0
// We can't retry if body is a stream, since it'll be drained
if (isStream(options.body)) {
return err
}
// Give up?
if (!shouldRetry(err, attemptNumber, options) || attemptNumber >= max) {
return err
}
// Create a new context with an increased attempt number, so we can exit if we reach a limit
const newContext = Object.assign({}, context, {
options: Object.assign({}, options, {attemptNumber: attemptNumber + 1}),
})
// Wait a given amount of time before doing the request again
setTimeout(() => context.channels.request.publish(newContext), delay(attemptNumber))
// Signal that we've handled the error and that it should not propagate further
return null
},
} satisfies Middleware
}
function getRetryDelay(attemptNum: number) {
return 100 * Math.pow(2, attemptNum) + Math.random() * 100
}