@aws-sdk/util-retry
Advanced tools
Comparing version 3.338.0 to 3.341.0
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getDefaultRetryToken = void 0; | ||
exports.createDefaultRetryToken = void 0; | ||
const constants_1 = require("./constants"); | ||
const defaultRetryBackoffStrategy_1 = require("./defaultRetryBackoffStrategy"); | ||
const getDefaultRetryToken = (initialRetryTokens, initialRetryDelay, initialRetryCount, options) => { | ||
var _a, _b, _c; | ||
const MAX_CAPACITY = initialRetryTokens; | ||
const retryCost = (_a = options === null || options === void 0 ? void 0 : options.retryCost) !== null && _a !== void 0 ? _a : constants_1.RETRY_COST; | ||
const timeoutRetryCost = (_b = options === null || options === void 0 ? void 0 : options.timeoutRetryCost) !== null && _b !== void 0 ? _b : constants_1.TIMEOUT_RETRY_COST; | ||
const retryBackoffStrategy = (_c = options === null || options === void 0 ? void 0 : options.retryBackoffStrategy) !== null && _c !== void 0 ? _c : (0, defaultRetryBackoffStrategy_1.getDefaultRetryBackoffStrategy)(); | ||
let availableCapacity = initialRetryTokens; | ||
let retryDelay = Math.min(constants_1.MAXIMUM_RETRY_DELAY, initialRetryDelay); | ||
let lastRetryCost = undefined; | ||
let retryCount = initialRetryCount !== null && initialRetryCount !== void 0 ? initialRetryCount : 0; | ||
const getCapacityAmount = (errorType) => (errorType === "TRANSIENT" ? timeoutRetryCost : retryCost); | ||
const createDefaultRetryToken = ({ retryDelay, retryCount, retryCost, }) => { | ||
const getRetryCount = () => retryCount; | ||
const getRetryDelay = () => retryDelay; | ||
const getLastRetryCost = () => lastRetryCost; | ||
const hasRetryTokens = (errorType) => getCapacityAmount(errorType) <= availableCapacity; | ||
const getRetryTokenCount = (errorInfo) => { | ||
const errorType = errorInfo.errorType; | ||
if (!hasRetryTokens(errorType)) { | ||
throw new Error("No retry token available"); | ||
} | ||
const capacityAmount = getCapacityAmount(errorType); | ||
const delayBase = errorType === "THROTTLING" ? constants_1.THROTTLING_RETRY_DELAY_BASE : constants_1.DEFAULT_RETRY_DELAY_BASE; | ||
retryBackoffStrategy.setDelayBase(delayBase); | ||
const delayFromErrorType = retryBackoffStrategy.computeNextBackoffDelay(retryCount); | ||
if (errorInfo.retryAfterHint) { | ||
const delayFromRetryAfterHint = errorInfo.retryAfterHint.getTime() - Date.now(); | ||
retryDelay = Math.max(delayFromRetryAfterHint || 0, delayFromErrorType); | ||
} | ||
else { | ||
retryDelay = delayFromErrorType; | ||
} | ||
retryCount++; | ||
lastRetryCost = capacityAmount; | ||
availableCapacity -= capacityAmount; | ||
return capacityAmount; | ||
}; | ||
const releaseRetryTokens = (releaseAmount) => { | ||
availableCapacity += releaseAmount !== null && releaseAmount !== void 0 ? releaseAmount : constants_1.NO_RETRY_INCREMENT; | ||
availableCapacity = Math.min(availableCapacity, MAX_CAPACITY); | ||
}; | ||
const getRetryDelay = () => Math.min(constants_1.MAXIMUM_RETRY_DELAY, retryDelay); | ||
const getRetryCost = () => retryCost; | ||
return { | ||
getRetryCount, | ||
getRetryDelay, | ||
getLastRetryCost, | ||
hasRetryTokens, | ||
getRetryTokenCount, | ||
releaseRetryTokens, | ||
getRetryCost, | ||
}; | ||
}; | ||
exports.getDefaultRetryToken = getDefaultRetryToken; | ||
exports.createDefaultRetryToken = createDefaultRetryToken; |
@@ -6,2 +6,3 @@ "use strict"; | ||
const constants_1 = require("./constants"); | ||
const defaultRetryBackoffStrategy_1 = require("./defaultRetryBackoffStrategy"); | ||
const defaultRetryToken_1 = require("./defaultRetryToken"); | ||
@@ -12,13 +13,28 @@ class StandardRetryStrategy { | ||
this.mode = config_1.RETRY_MODES.STANDARD; | ||
this.retryToken = (0, defaultRetryToken_1.getDefaultRetryToken)(constants_1.INITIAL_RETRY_TOKENS, constants_1.DEFAULT_RETRY_DELAY_BASE); | ||
this.capacity = constants_1.INITIAL_RETRY_TOKENS; | ||
this.retryBackoffStrategy = (0, defaultRetryBackoffStrategy_1.getDefaultRetryBackoffStrategy)(); | ||
this.maxAttemptsProvider = typeof maxAttempts === "function" ? maxAttempts : async () => maxAttempts; | ||
} | ||
async acquireInitialRetryToken(retryTokenScope) { | ||
return this.retryToken; | ||
return (0, defaultRetryToken_1.createDefaultRetryToken)({ | ||
retryDelay: constants_1.DEFAULT_RETRY_DELAY_BASE, | ||
retryCount: 0, | ||
}); | ||
} | ||
async refreshRetryTokenForRetry(tokenToRenew, errorInfo) { | ||
async refreshRetryTokenForRetry(token, errorInfo) { | ||
const maxAttempts = await this.getMaxAttempts(); | ||
if (this.shouldRetry(tokenToRenew, errorInfo, maxAttempts)) { | ||
tokenToRenew.getRetryTokenCount(errorInfo); | ||
return tokenToRenew; | ||
if (this.shouldRetry(token, errorInfo, maxAttempts)) { | ||
const errorType = errorInfo.errorType; | ||
this.retryBackoffStrategy.setDelayBase(errorType === "THROTTLING" ? constants_1.THROTTLING_RETRY_DELAY_BASE : constants_1.DEFAULT_RETRY_DELAY_BASE); | ||
const delayFromErrorType = this.retryBackoffStrategy.computeNextBackoffDelay(token.getRetryCount()); | ||
const retryDelay = errorInfo.retryAfterHint | ||
? Math.max(errorInfo.retryAfterHint.getTime() - Date.now() || 0, delayFromErrorType) | ||
: delayFromErrorType; | ||
const capacityCost = this.getCapacityCost(errorType); | ||
this.capacity -= capacityCost; | ||
return (0, defaultRetryToken_1.createDefaultRetryToken)({ | ||
retryDelay, | ||
retryCount: token.getRetryCount() + 1, | ||
retryCost: capacityCost, | ||
}); | ||
} | ||
@@ -28,6 +44,9 @@ throw new Error("No retry token available"); | ||
recordSuccess(token) { | ||
this.retryToken.releaseRetryTokens(token.getLastRetryCost()); | ||
var _a; | ||
this.capacity = Math.max(constants_1.INITIAL_RETRY_TOKENS, this.capacity + ((_a = token.getRetryCost()) !== null && _a !== void 0 ? _a : constants_1.NO_RETRY_INCREMENT)); | ||
} | ||
getCapacity() { | ||
return this.capacity; | ||
} | ||
async getMaxAttempts() { | ||
let maxAttempts; | ||
try { | ||
@@ -44,5 +63,8 @@ return await this.maxAttemptsProvider(); | ||
return (attempts < maxAttempts && | ||
tokenToRenew.hasRetryTokens(errorInfo.errorType) && | ||
this.capacity >= this.getCapacityCost(errorInfo.errorType) && | ||
this.isRetryableError(errorInfo.errorType)); | ||
} | ||
getCapacityCost(errorType) { | ||
return errorType === "TRANSIENT" ? constants_1.TIMEOUT_RETRY_COST : constants_1.RETRY_COST; | ||
} | ||
isRetryableError(errorType) { | ||
@@ -49,0 +71,0 @@ return errorType === "THROTTLING" || errorType === "TRANSIENT"; |
@@ -1,50 +0,11 @@ | ||
import { DEFAULT_RETRY_DELAY_BASE, MAXIMUM_RETRY_DELAY, NO_RETRY_INCREMENT, RETRY_COST, THROTTLING_RETRY_DELAY_BASE, TIMEOUT_RETRY_COST, } from "./constants"; | ||
import { getDefaultRetryBackoffStrategy } from "./defaultRetryBackoffStrategy"; | ||
export const getDefaultRetryToken = (initialRetryTokens, initialRetryDelay, initialRetryCount, options) => { | ||
const MAX_CAPACITY = initialRetryTokens; | ||
const retryCost = options?.retryCost ?? RETRY_COST; | ||
const timeoutRetryCost = options?.timeoutRetryCost ?? TIMEOUT_RETRY_COST; | ||
const retryBackoffStrategy = options?.retryBackoffStrategy ?? getDefaultRetryBackoffStrategy(); | ||
let availableCapacity = initialRetryTokens; | ||
let retryDelay = Math.min(MAXIMUM_RETRY_DELAY, initialRetryDelay); | ||
let lastRetryCost = undefined; | ||
let retryCount = initialRetryCount ?? 0; | ||
const getCapacityAmount = (errorType) => (errorType === "TRANSIENT" ? timeoutRetryCost : retryCost); | ||
import { MAXIMUM_RETRY_DELAY } from "./constants"; | ||
export const createDefaultRetryToken = ({ retryDelay, retryCount, retryCost, }) => { | ||
const getRetryCount = () => retryCount; | ||
const getRetryDelay = () => retryDelay; | ||
const getLastRetryCost = () => lastRetryCost; | ||
const hasRetryTokens = (errorType) => getCapacityAmount(errorType) <= availableCapacity; | ||
const getRetryTokenCount = (errorInfo) => { | ||
const errorType = errorInfo.errorType; | ||
if (!hasRetryTokens(errorType)) { | ||
throw new Error("No retry token available"); | ||
} | ||
const capacityAmount = getCapacityAmount(errorType); | ||
const delayBase = errorType === "THROTTLING" ? THROTTLING_RETRY_DELAY_BASE : DEFAULT_RETRY_DELAY_BASE; | ||
retryBackoffStrategy.setDelayBase(delayBase); | ||
const delayFromErrorType = retryBackoffStrategy.computeNextBackoffDelay(retryCount); | ||
if (errorInfo.retryAfterHint) { | ||
const delayFromRetryAfterHint = errorInfo.retryAfterHint.getTime() - Date.now(); | ||
retryDelay = Math.max(delayFromRetryAfterHint || 0, delayFromErrorType); | ||
} | ||
else { | ||
retryDelay = delayFromErrorType; | ||
} | ||
retryCount++; | ||
lastRetryCost = capacityAmount; | ||
availableCapacity -= capacityAmount; | ||
return capacityAmount; | ||
}; | ||
const releaseRetryTokens = (releaseAmount) => { | ||
availableCapacity += releaseAmount ?? NO_RETRY_INCREMENT; | ||
availableCapacity = Math.min(availableCapacity, MAX_CAPACITY); | ||
}; | ||
const getRetryDelay = () => Math.min(MAXIMUM_RETRY_DELAY, retryDelay); | ||
const getRetryCost = () => retryCost; | ||
return { | ||
getRetryCount, | ||
getRetryDelay, | ||
getLastRetryCost, | ||
hasRetryTokens, | ||
getRetryTokenCount, | ||
releaseRetryTokens, | ||
getRetryCost, | ||
}; | ||
}; |
import { DEFAULT_MAX_ATTEMPTS, RETRY_MODES } from "./config"; | ||
import { DEFAULT_RETRY_DELAY_BASE, INITIAL_RETRY_TOKENS } from "./constants"; | ||
import { getDefaultRetryToken } from "./defaultRetryToken"; | ||
import { DEFAULT_RETRY_DELAY_BASE, INITIAL_RETRY_TOKENS, NO_RETRY_INCREMENT, RETRY_COST, THROTTLING_RETRY_DELAY_BASE, TIMEOUT_RETRY_COST, } from "./constants"; | ||
import { getDefaultRetryBackoffStrategy } from "./defaultRetryBackoffStrategy"; | ||
import { createDefaultRetryToken } from "./defaultRetryToken"; | ||
export class StandardRetryStrategy { | ||
@@ -8,13 +9,28 @@ constructor(maxAttempts) { | ||
this.mode = RETRY_MODES.STANDARD; | ||
this.retryToken = getDefaultRetryToken(INITIAL_RETRY_TOKENS, DEFAULT_RETRY_DELAY_BASE); | ||
this.capacity = INITIAL_RETRY_TOKENS; | ||
this.retryBackoffStrategy = getDefaultRetryBackoffStrategy(); | ||
this.maxAttemptsProvider = typeof maxAttempts === "function" ? maxAttempts : async () => maxAttempts; | ||
} | ||
async acquireInitialRetryToken(retryTokenScope) { | ||
return this.retryToken; | ||
return createDefaultRetryToken({ | ||
retryDelay: DEFAULT_RETRY_DELAY_BASE, | ||
retryCount: 0, | ||
}); | ||
} | ||
async refreshRetryTokenForRetry(tokenToRenew, errorInfo) { | ||
async refreshRetryTokenForRetry(token, errorInfo) { | ||
const maxAttempts = await this.getMaxAttempts(); | ||
if (this.shouldRetry(tokenToRenew, errorInfo, maxAttempts)) { | ||
tokenToRenew.getRetryTokenCount(errorInfo); | ||
return tokenToRenew; | ||
if (this.shouldRetry(token, errorInfo, maxAttempts)) { | ||
const errorType = errorInfo.errorType; | ||
this.retryBackoffStrategy.setDelayBase(errorType === "THROTTLING" ? THROTTLING_RETRY_DELAY_BASE : DEFAULT_RETRY_DELAY_BASE); | ||
const delayFromErrorType = this.retryBackoffStrategy.computeNextBackoffDelay(token.getRetryCount()); | ||
const retryDelay = errorInfo.retryAfterHint | ||
? Math.max(errorInfo.retryAfterHint.getTime() - Date.now() || 0, delayFromErrorType) | ||
: delayFromErrorType; | ||
const capacityCost = this.getCapacityCost(errorType); | ||
this.capacity -= capacityCost; | ||
return createDefaultRetryToken({ | ||
retryDelay, | ||
retryCount: token.getRetryCount() + 1, | ||
retryCost: capacityCost, | ||
}); | ||
} | ||
@@ -24,6 +40,8 @@ throw new Error("No retry token available"); | ||
recordSuccess(token) { | ||
this.retryToken.releaseRetryTokens(token.getLastRetryCost()); | ||
this.capacity = Math.max(INITIAL_RETRY_TOKENS, this.capacity + (token.getRetryCost() ?? NO_RETRY_INCREMENT)); | ||
} | ||
getCapacity() { | ||
return this.capacity; | ||
} | ||
async getMaxAttempts() { | ||
let maxAttempts; | ||
try { | ||
@@ -40,5 +58,8 @@ return await this.maxAttemptsProvider(); | ||
return (attempts < maxAttempts && | ||
tokenToRenew.hasRetryTokens(errorInfo.errorType) && | ||
this.capacity >= this.getCapacityCost(errorInfo.errorType) && | ||
this.isRetryableError(errorInfo.errorType)); | ||
} | ||
getCapacityCost(errorType) { | ||
return errorType === "TRANSIENT" ? TIMEOUT_RETRY_COST : RETRY_COST; | ||
} | ||
isRetryableError(errorType) { | ||
@@ -45,0 +66,0 @@ return errorType === "THROTTLING" || errorType === "TRANSIENT"; |
@@ -1,23 +0,9 @@ | ||
import { StandardRetryBackoffStrategy, StandardRetryToken } from "@aws-sdk/types"; | ||
import { StandardRetryToken } from "@aws-sdk/types"; | ||
/** | ||
* @public | ||
*/ | ||
export interface DefaultRetryTokenOptions { | ||
/** | ||
* The total amount of retry tokens to be decremented from retry token balance. | ||
*/ | ||
retryCost?: number; | ||
/** | ||
* The total amount of retry tokens to be decremented from retry token balance | ||
* when a throttling error is encountered. | ||
*/ | ||
timeoutRetryCost?: number; | ||
/** | ||
* | ||
*/ | ||
retryBackoffStrategy?: StandardRetryBackoffStrategy; | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
export declare const getDefaultRetryToken: (initialRetryTokens: number, initialRetryDelay: number, initialRetryCount?: number, options?: DefaultRetryTokenOptions) => StandardRetryToken; | ||
export declare const createDefaultRetryToken: ({ retryDelay, retryCount, retryCost, }: { | ||
retryDelay: number; | ||
retryCount: number; | ||
retryCost?: number | undefined; | ||
}) => StandardRetryToken; |
@@ -8,3 +8,4 @@ import { Provider, RetryErrorInfo, RetryStrategyV2, StandardRetryToken } from "@aws-sdk/types"; | ||
readonly mode: string; | ||
private retryToken; | ||
private capacity; | ||
private readonly retryBackoffStrategy; | ||
private readonly maxAttemptsProvider; | ||
@@ -14,7 +15,14 @@ constructor(maxAttempts: number); | ||
acquireInitialRetryToken(retryTokenScope: string): Promise<StandardRetryToken>; | ||
refreshRetryTokenForRetry(tokenToRenew: StandardRetryToken, errorInfo: RetryErrorInfo): Promise<StandardRetryToken>; | ||
refreshRetryTokenForRetry(token: StandardRetryToken, errorInfo: RetryErrorInfo): Promise<StandardRetryToken>; | ||
recordSuccess(token: StandardRetryToken): void; | ||
/** | ||
* @returns the current available retry capacity. | ||
* | ||
* This number decreases when retries are executed and refills when requests or retries succeed. | ||
*/ | ||
getCapacity(): number; | ||
private getMaxAttempts; | ||
private shouldRetry; | ||
private getCapacityCost; | ||
private isRetryableError; | ||
} |
@@ -1,15 +0,10 @@ | ||
import { | ||
StandardRetryBackoffStrategy, | ||
StandardRetryToken, | ||
} from "@aws-sdk/types"; | ||
export interface DefaultRetryTokenOptions { | ||
retryCost?: number; | ||
timeoutRetryCost?: number; | ||
retryBackoffStrategy?: StandardRetryBackoffStrategy; | ||
} | ||
export declare const getDefaultRetryToken: ( | ||
initialRetryTokens: number, | ||
initialRetryDelay: number, | ||
initialRetryCount?: number, | ||
options?: DefaultRetryTokenOptions | ||
) => StandardRetryToken; | ||
import { StandardRetryToken } from "@aws-sdk/types"; | ||
export declare const createDefaultRetryToken: ({ | ||
retryDelay, | ||
retryCount, | ||
retryCost, | ||
}: { | ||
retryDelay: number; | ||
retryCount: number; | ||
retryCost?: number | undefined; | ||
}) => StandardRetryToken; |
@@ -10,3 +10,4 @@ import { | ||
readonly mode: string; | ||
private retryToken; | ||
private capacity; | ||
private readonly retryBackoffStrategy; | ||
private readonly maxAttemptsProvider; | ||
@@ -19,9 +20,11 @@ constructor(maxAttempts: number); | ||
refreshRetryTokenForRetry( | ||
tokenToRenew: StandardRetryToken, | ||
token: StandardRetryToken, | ||
errorInfo: RetryErrorInfo | ||
): Promise<StandardRetryToken>; | ||
recordSuccess(token: StandardRetryToken): void; | ||
getCapacity(): number; | ||
private getMaxAttempts; | ||
private shouldRetry; | ||
private getCapacityCost; | ||
private isRetryableError; | ||
} |
{ | ||
"name": "@aws-sdk/util-retry", | ||
"version": "3.338.0", | ||
"version": "3.341.0", | ||
"description": "Shared retry utilities to be used in middleware packages.", | ||
@@ -28,7 +28,7 @@ "main": "./dist-cjs/index.js", | ||
"dependencies": { | ||
"@aws-sdk/service-error-classification": "3.338.0", | ||
"@aws-sdk/service-error-classification": "3.341.0", | ||
"tslib": "^2.5.0" | ||
}, | ||
"devDependencies": { | ||
"@aws-sdk/types": "3.338.0", | ||
"@aws-sdk/types": "3.341.0", | ||
"@tsconfig/recommended": "1.0.1", | ||
@@ -35,0 +35,0 @@ "@types/node": "^14.14.31", |
52725
958
+ Added@aws-sdk/service-error-classification@3.341.0(transitive)
- Removed@aws-sdk/service-error-classification@3.338.0(transitive)