UNPKG

@aws-amplify/core

Version:
96 lines (94 loc) 3.7 kB
'use strict'; // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 Object.defineProperty(exports, "__esModule", { value: true }); exports.retryMiddlewareFactory = void 0; const DEFAULT_RETRY_ATTEMPTS = 3; /** * Retry middleware */ const retryMiddlewareFactory = ({ maxAttempts = DEFAULT_RETRY_ATTEMPTS, retryDecider, computeDelay, abortSignal, }) => { if (maxAttempts < 1) { throw new Error('maxAttempts must be greater than 0'); } return (next, context) => async function retryMiddleware(request) { let error; let attemptsCount = context.attemptsCount ?? 0; let response; // When retry is not needed or max attempts is reached, either error or response will be set. This function handles either cases. const handleTerminalErrorOrResponse = () => { if (response) { addOrIncrementMetadataAttempts(response, attemptsCount); return response; } else { addOrIncrementMetadataAttempts(error, attemptsCount); throw error; } }; while (!abortSignal?.aborted && attemptsCount < maxAttempts) { try { response = await next(request); error = undefined; } catch (e) { error = e; response = undefined; } // context.attemptsCount may be updated after calling next handler which may retry the request by itself. attemptsCount = (context.attemptsCount ?? 0) > attemptsCount ? (context.attemptsCount ?? 0) : attemptsCount + 1; context.attemptsCount = attemptsCount; const { isCredentialsExpiredError, retryable } = await retryDecider(response, error, context); if (retryable) { // Setting isCredentialsInvalid flag to notify signing middleware to forceRefresh credentials provider. context.isCredentialsExpired = !!isCredentialsExpiredError; if (!abortSignal?.aborted && attemptsCount < maxAttempts) { // prevent sleep for last attempt or cancelled request; const delay = computeDelay(attemptsCount); await cancellableSleep(delay, abortSignal); } continue; } else { return handleTerminalErrorOrResponse(); } } if (abortSignal?.aborted) { throw new Error('Request aborted.'); } else { return handleTerminalErrorOrResponse(); } }; }; exports.retryMiddlewareFactory = retryMiddlewareFactory; const cancellableSleep = (timeoutMs, abortSignal) => { if (abortSignal?.aborted) { return Promise.resolve(); } let timeoutId; let sleepPromiseResolveFn; const sleepPromise = new Promise(resolve => { sleepPromiseResolveFn = resolve; timeoutId = setTimeout(resolve, timeoutMs); }); abortSignal?.addEventListener('abort', function cancelSleep(_) { clearTimeout(timeoutId); abortSignal?.removeEventListener('abort', cancelSleep); sleepPromiseResolveFn(); }); return sleepPromise; }; const addOrIncrementMetadataAttempts = (nextHandlerOutput, attempts) => { if (Object.prototype.toString.call(nextHandlerOutput) !== '[object Object]') { return; } nextHandlerOutput.$metadata = { ...(nextHandlerOutput.$metadata ?? {}), attempts, }; }; //# sourceMappingURL=middleware.js.map