retry-axios
Version:
Retry HTTP requests with Axios.
195 lines (193 loc) • 6.63 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// build/src/index.js
var index_exports = {};
__export(index_exports, {
attach: () => attach,
detach: () => detach,
getConfig: () => getConfig,
shouldRetryRequest: () => shouldRetryRequest
});
module.exports = __toCommonJS(index_exports);
var import_axios = __toESM(require("axios"), 1);
var retryRanges = [
// https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
// 1xx - Retry (Informational, request still processing)
// 2xx - Do not retry (Success)
// 3xx - Do not retry (Redirect)
// 4xx - Do not retry (Client errors)
// 429 - Retry ("Too Many Requests")
// 5xx - Retry (Server errors)
[100, 199],
[429, 429],
[500, 599]
];
function attach(instance) {
const inst = instance || import_axios.default;
return inst.interceptors.response.use(onFulfilled, async (error) => onError(inst, error));
}
function detach(interceptorId, instance) {
const inst = instance || import_axios.default;
inst.interceptors.response.eject(interceptorId);
}
function onFulfilled(result) {
return result;
}
function normalizeArray(object) {
const array = [];
if (!object) {
return void 0;
}
if (Array.isArray(object)) {
return object;
}
if (typeof object === "object") {
for (const key of Object.keys(object)) {
const number_ = Number.parseInt(key, 10);
if (!Number.isNaN(number_)) {
array[number_] = object[key];
}
}
}
return array;
}
function parseRetryAfter(header) {
const value = Number(header);
if (!Number.isNaN(value)) {
return value * 1e3;
}
const dateTime = Date.parse(header);
if (!Number.isNaN(dateTime)) {
return dateTime - Date.now();
}
return void 0;
}
async function onError(instance, error) {
if ((0, import_axios.isCancel)(error)) {
throw error;
}
const config = getConfig(error) || {};
config.currentRetryAttempt ||= 0;
config.retry = typeof config.retry === "number" ? config.retry : 3;
config.retryDelay = typeof config.retryDelay === "number" ? config.retryDelay : 100;
config.instance ||= instance;
config.backoffType ||= "exponential";
config.httpMethodsToRetry = normalizeArray(config.httpMethodsToRetry) || [
"GET",
"HEAD",
"PUT",
"OPTIONS",
"DELETE"
];
config.noResponseRetries = typeof config.noResponseRetries === "number" ? config.noResponseRetries : 2;
config.checkRetryAfter = typeof config.checkRetryAfter === "boolean" ? config.checkRetryAfter : true;
config.maxRetryAfter = typeof config.maxRetryAfter === "number" ? config.maxRetryAfter : 6e4 * 5;
config.statusCodesToRetry = normalizeArray(config.statusCodesToRetry) || retryRanges;
const axiosError = error;
axiosError.config = axiosError.config || {};
axiosError.config.raxConfig = { ...config };
const shouldRetryFunction = config.shouldRetry || shouldRetryRequest;
if (!shouldRetryFunction(axiosError)) {
throw axiosError;
}
const onBackoffPromise = new Promise((resolve, reject) => {
let delay = 0;
if (config.checkRetryAfter && axiosError.response?.headers?.["retry-after"]) {
const retryAfter = parseRetryAfter(axiosError.response.headers["retry-after"]);
if (retryAfter && retryAfter > 0 && retryAfter <= (config.maxRetryAfter ?? 0)) {
delay = retryAfter;
} else {
reject(axiosError);
return;
}
}
axiosError.config.raxConfig.currentRetryAttempt += 1;
const retrycount = axiosError.config.raxConfig.currentRetryAttempt;
if (delay === 0) {
if (config.backoffType === "linear") {
delay = retrycount * 1e3;
} else if (config.backoffType === "static") {
delay = config.retryDelay;
} else {
delay = (2 ** retrycount - 1) / 2 * 1e3;
}
if (typeof config.maxRetryDelay === "number") {
delay = Math.min(delay, config.maxRetryDelay);
}
}
setTimeout(resolve, delay);
});
if (config.onRetryAttempt) {
config.onRetryAttempt(axiosError);
}
const onRetryAttemptPromise = Promise.resolve();
return Promise.resolve().then(async () => onBackoffPromise).then(async () => onRetryAttemptPromise).then(async () => config.instance?.request(axiosError.config));
}
function shouldRetryRequest(error) {
const config = error.config.raxConfig;
if (!config || config.retry === 0) {
return false;
}
if (!error.response && (config.currentRetryAttempt || 0) >= (config.noResponseRetries ?? 0)) {
return false;
}
if (!error.config?.method || !config.httpMethodsToRetry?.includes(error.config.method.toUpperCase())) {
return false;
}
if (error.response?.status) {
let isInRange = false;
for (const [min, max] of config.statusCodesToRetry) {
const { status } = error.response;
if (status >= min && status <= max) {
isInRange = true;
break;
}
}
if (!isInRange) {
return false;
}
}
config.currentRetryAttempt ||= 0;
if (config.currentRetryAttempt >= (config.retry ?? 0)) {
return false;
}
return true;
}
function getConfig(error) {
if (error?.config) {
return error.config.raxConfig;
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
attach,
detach,
getConfig,
shouldRetryRequest
});
;