Skip to content

Commit

Permalink
feat: add support for retry-after header
Browse files Browse the repository at this point in the history
  • Loading branch information
metcoder95 committed Oct 25, 2023
1 parent 0fc9518 commit b8fbef0
Show file tree
Hide file tree
Showing 2 changed files with 564 additions and 253 deletions.
33 changes: 27 additions & 6 deletions lib/handler/RetryHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ const {
safeHTTPMethods
} = require('../core/util')

function calculateRetryAfterHeader (retryAfter) {
const current = Date.now()
const diff = new Date(retryAfter).getTime() - current

return diff
}

class RetryHandler {
constructor (opts, handlers, retryOpts) {
const {
Expand All @@ -22,6 +29,7 @@ class RetryHandler {
methods,
idempotent,
codes,
retryAfter,
status: statusCodes
} = retryOpts ?? {}

Expand All @@ -32,6 +40,7 @@ class RetryHandler {
this.aborted = false
this.retryOpts = {
retry: retryFn ?? RetryHandler[kRetryHandlerDefaultRetry],
retryAfter: retryAfter ?? true,
maxTimeout: maxTimeout ?? 30 * 1000, // 30s,
timeout: minTimeout ?? 500, // .5s
timeoutFactor: timeoutFactor ?? 2,
Expand All @@ -41,7 +50,7 @@ class RetryHandler {
// States weather or not retry on idempotent methods
idempotent: idempotent ?? false,
// Indicates which errors to retry
status: statusCodes ?? [500, 502, 503, 504],
status: statusCodes ?? [500, 502, 503, 504, 429],
// List of errors to retry
codes: codes ?? [
'ECONNRESET',
Expand Down Expand Up @@ -88,10 +97,11 @@ class RetryHandler {
}

static [kRetryHandlerDefaultRetry] (err, { counter, currentTimeout }, opts) {
const { statusCode, code } = err
const { statusCode, code, headers } = err
const { method } = opts
const {
max,
timeout,
maxTimeout,
timeoutFactor,
status,
Expand All @@ -100,6 +110,9 @@ class RetryHandler {
methods
} = opts.retry

currentTimeout =
currentTimeout != null && currentTimeout > 0 ? currentTimeout : timeout

// Any code that is not a Undici's originated and allowed to retry
if (
code &&
Expand Down Expand Up @@ -128,10 +141,18 @@ class RetryHandler {
// If we reached the max number of retries
if (counter > max) return null

const retryTimeout = Math.min(
currentTimeout * timeoutFactor ** counter,
maxTimeout
)
let retryAfterHeader = headers != null && headers['retry-after']
if (retryAfterHeader) {
retryAfterHeader = Number(retryAfterHeader)
retryAfterHeader = isNaN(retryAfterHeader)
? calculateRetryAfterHeader(retryAfterHeader)
: retryAfterHeader * 1e3 // Retry-After is in seconds
}

const retryTimeout =
retryAfterHeader > 0
? Math.min(retryAfterHeader, maxTimeout)
: Math.min(currentTimeout * timeoutFactor ** counter, maxTimeout)

return retryTimeout
}
Expand Down

0 comments on commit b8fbef0

Please sign in to comment.