aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/node_modules/undici/lib/handler/RetryHandler.js
diff options
context:
space:
mode:
authorEgor Tensin <egor@tensin.name>2026-02-28 21:59:12 +0100
committerEgor Tensin <egor@tensin.name>2026-02-28 22:19:57 +0100
commit9611c248995ad3bacda1d0a93d0b5e1e6605d162 (patch)
treeeb3ae35b426e9d72e7cb34e8e9cc0453745a8e17 /node_modules/undici/lib/handler/RetryHandler.js
parentDEVELOPMENT.md: expand on sources (diff)
downloadcleanup-path-9611c248995ad3bacda1d0a93d0b5e1e6605d162.tar.gz
cleanup-path-9611c248995ad3bacda1d0a93d0b5e1e6605d162.zip
upgrade actions/core to version 2
Diffstat (limited to 'node_modules/undici/lib/handler/RetryHandler.js')
-rw-r--r--node_modules/undici/lib/handler/RetryHandler.js336
1 files changed, 0 insertions, 336 deletions
diff --git a/node_modules/undici/lib/handler/RetryHandler.js b/node_modules/undici/lib/handler/RetryHandler.js
deleted file mode 100644
index 3710447..0000000
--- a/node_modules/undici/lib/handler/RetryHandler.js
+++ /dev/null
@@ -1,336 +0,0 @@
-const assert = require('assert')
-
-const { kRetryHandlerDefaultRetry } = require('../core/symbols')
-const { RequestRetryError } = require('../core/errors')
-const { isDisturbed, parseHeaders, parseRangeHeader } = require('../core/util')
-
-function calculateRetryAfterHeader (retryAfter) {
- const current = Date.now()
- const diff = new Date(retryAfter).getTime() - current
-
- return diff
-}
-
-class RetryHandler {
- constructor (opts, handlers) {
- const { retryOptions, ...dispatchOpts } = opts
- const {
- // Retry scoped
- retry: retryFn,
- maxRetries,
- maxTimeout,
- minTimeout,
- timeoutFactor,
- // Response scoped
- methods,
- errorCodes,
- retryAfter,
- statusCodes
- } = retryOptions ?? {}
-
- this.dispatch = handlers.dispatch
- this.handler = handlers.handler
- this.opts = dispatchOpts
- this.abort = null
- this.aborted = false
- this.retryOpts = {
- retry: retryFn ?? RetryHandler[kRetryHandlerDefaultRetry],
- retryAfter: retryAfter ?? true,
- maxTimeout: maxTimeout ?? 30 * 1000, // 30s,
- timeout: minTimeout ?? 500, // .5s
- timeoutFactor: timeoutFactor ?? 2,
- maxRetries: maxRetries ?? 5,
- // What errors we should retry
- methods: methods ?? ['GET', 'HEAD', 'OPTIONS', 'PUT', 'DELETE', 'TRACE'],
- // Indicates which errors to retry
- statusCodes: statusCodes ?? [500, 502, 503, 504, 429],
- // List of errors to retry
- errorCodes: errorCodes ?? [
- 'ECONNRESET',
- 'ECONNREFUSED',
- 'ENOTFOUND',
- 'ENETDOWN',
- 'ENETUNREACH',
- 'EHOSTDOWN',
- 'EHOSTUNREACH',
- 'EPIPE'
- ]
- }
-
- this.retryCount = 0
- this.start = 0
- this.end = null
- this.etag = null
- this.resume = null
-
- // Handle possible onConnect duplication
- this.handler.onConnect(reason => {
- this.aborted = true
- if (this.abort) {
- this.abort(reason)
- } else {
- this.reason = reason
- }
- })
- }
-
- onRequestSent () {
- if (this.handler.onRequestSent) {
- this.handler.onRequestSent()
- }
- }
-
- onUpgrade (statusCode, headers, socket) {
- if (this.handler.onUpgrade) {
- this.handler.onUpgrade(statusCode, headers, socket)
- }
- }
-
- onConnect (abort) {
- if (this.aborted) {
- abort(this.reason)
- } else {
- this.abort = abort
- }
- }
-
- onBodySent (chunk) {
- if (this.handler.onBodySent) return this.handler.onBodySent(chunk)
- }
-
- static [kRetryHandlerDefaultRetry] (err, { state, opts }, cb) {
- const { statusCode, code, headers } = err
- const { method, retryOptions } = opts
- const {
- maxRetries,
- timeout,
- maxTimeout,
- timeoutFactor,
- statusCodes,
- errorCodes,
- methods
- } = retryOptions
- let { counter, currentTimeout } = state
-
- currentTimeout =
- currentTimeout != null && currentTimeout > 0 ? currentTimeout : timeout
-
- // Any code that is not a Undici's originated and allowed to retry
- if (
- code &&
- code !== 'UND_ERR_REQ_RETRY' &&
- code !== 'UND_ERR_SOCKET' &&
- !errorCodes.includes(code)
- ) {
- cb(err)
- return
- }
-
- // If a set of method are provided and the current method is not in the list
- if (Array.isArray(methods) && !methods.includes(method)) {
- cb(err)
- return
- }
-
- // If a set of status code are provided and the current status code is not in the list
- if (
- statusCode != null &&
- Array.isArray(statusCodes) &&
- !statusCodes.includes(statusCode)
- ) {
- cb(err)
- return
- }
-
- // If we reached the max number of retries
- if (counter > maxRetries) {
- cb(err)
- return
- }
-
- 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)
-
- state.currentTimeout = retryTimeout
-
- setTimeout(() => cb(null), retryTimeout)
- }
-
- onHeaders (statusCode, rawHeaders, resume, statusMessage) {
- const headers = parseHeaders(rawHeaders)
-
- this.retryCount += 1
-
- if (statusCode >= 300) {
- this.abort(
- new RequestRetryError('Request failed', statusCode, {
- headers,
- count: this.retryCount
- })
- )
- return false
- }
-
- // Checkpoint for resume from where we left it
- if (this.resume != null) {
- this.resume = null
-
- if (statusCode !== 206) {
- return true
- }
-
- const contentRange = parseRangeHeader(headers['content-range'])
- // If no content range
- if (!contentRange) {
- this.abort(
- new RequestRetryError('Content-Range mismatch', statusCode, {
- headers,
- count: this.retryCount
- })
- )
- return false
- }
-
- // Let's start with a weak etag check
- if (this.etag != null && this.etag !== headers.etag) {
- this.abort(
- new RequestRetryError('ETag mismatch', statusCode, {
- headers,
- count: this.retryCount
- })
- )
- return false
- }
-
- const { start, size, end = size } = contentRange
-
- assert(this.start === start, 'content-range mismatch')
- assert(this.end == null || this.end === end, 'content-range mismatch')
-
- this.resume = resume
- return true
- }
-
- if (this.end == null) {
- if (statusCode === 206) {
- // First time we receive 206
- const range = parseRangeHeader(headers['content-range'])
-
- if (range == null) {
- return this.handler.onHeaders(
- statusCode,
- rawHeaders,
- resume,
- statusMessage
- )
- }
-
- const { start, size, end = size } = range
-
- assert(
- start != null && Number.isFinite(start) && this.start !== start,
- 'content-range mismatch'
- )
- assert(Number.isFinite(start))
- assert(
- end != null && Number.isFinite(end) && this.end !== end,
- 'invalid content-length'
- )
-
- this.start = start
- this.end = end
- }
-
- // We make our best to checkpoint the body for further range headers
- if (this.end == null) {
- const contentLength = headers['content-length']
- this.end = contentLength != null ? Number(contentLength) : null
- }
-
- assert(Number.isFinite(this.start))
- assert(
- this.end == null || Number.isFinite(this.end),
- 'invalid content-length'
- )
-
- this.resume = resume
- this.etag = headers.etag != null ? headers.etag : null
-
- return this.handler.onHeaders(
- statusCode,
- rawHeaders,
- resume,
- statusMessage
- )
- }
-
- const err = new RequestRetryError('Request failed', statusCode, {
- headers,
- count: this.retryCount
- })
-
- this.abort(err)
-
- return false
- }
-
- onData (chunk) {
- this.start += chunk.length
-
- return this.handler.onData(chunk)
- }
-
- onComplete (rawTrailers) {
- this.retryCount = 0
- return this.handler.onComplete(rawTrailers)
- }
-
- onError (err) {
- if (this.aborted || isDisturbed(this.opts.body)) {
- return this.handler.onError(err)
- }
-
- this.retryOpts.retry(
- err,
- {
- state: { counter: this.retryCount++, currentTimeout: this.retryAfter },
- opts: { retryOptions: this.retryOpts, ...this.opts }
- },
- onRetry.bind(this)
- )
-
- function onRetry (err) {
- if (err != null || this.aborted || isDisturbed(this.opts.body)) {
- return this.handler.onError(err)
- }
-
- if (this.start !== 0) {
- this.opts = {
- ...this.opts,
- headers: {
- ...this.opts.headers,
- range: `bytes=${this.start}-${this.end ?? ''}`
- }
- }
- }
-
- try {
- this.dispatch(this.opts, this)
- } catch (err) {
- this.handler.onError(err)
- }
- }
- }
-}
-
-module.exports = RetryHandler