UNPKG

@azure/core-rest-pipeline

Version:

Isomorphic client library for making HTTP requests in node.js and browser.

105 lines 5.42 kB
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. import { delay } from "../util/helpers.js"; import { createClientLogger } from "@azure/logger"; import { AbortError } from "@azure/abort-controller"; import { DEFAULT_RETRY_POLICY_COUNT } from "../constants.js"; const retryPolicyLogger = createClientLogger("core-rest-pipeline retryPolicy"); /** * The programmatic identifier of the retryPolicy. */ const retryPolicyName = "retryPolicy"; /** * retryPolicy is a generic policy to enable retrying requests when certain conditions are met */ export function retryPolicy(strategies, options = { maxRetries: DEFAULT_RETRY_POLICY_COUNT }) { const logger = options.logger || retryPolicyLogger; return { name: retryPolicyName, async sendRequest(request, next) { var _a, _b; let response; let responseError; let retryCount = -1; retryRequest: while (true) { retryCount += 1; response = undefined; responseError = undefined; try { logger.info(`Retry ${retryCount}: Attempting to send request`, request.requestId); response = await next(request); logger.info(`Retry ${retryCount}: Received a response from request`, request.requestId); } catch (e) { logger.error(`Retry ${retryCount}: Received an error from request`, request.requestId); // RestErrors are valid targets for the retry strategies. // If none of the retry strategies can work with them, they will be thrown later in this policy. // If the received error is not a RestError, it is immediately thrown. responseError = e; if (!e || responseError.name !== "RestError") { throw e; } response = responseError.response; } if ((_a = request.abortSignal) === null || _a === void 0 ? void 0 : _a.aborted) { logger.error(`Retry ${retryCount}: Request aborted.`); const abortError = new AbortError(); throw abortError; } if (retryCount >= ((_b = options.maxRetries) !== null && _b !== void 0 ? _b : DEFAULT_RETRY_POLICY_COUNT)) { logger.info(`Retry ${retryCount}: Maximum retries reached. Returning the last received response, or throwing the last received error.`); if (responseError) { throw responseError; } else if (response) { return response; } else { throw new Error("Maximum retries reached with no response or error to throw"); } } logger.info(`Retry ${retryCount}: Processing ${strategies.length} retry strategies.`); strategiesLoop: for (const strategy of strategies) { const strategyLogger = strategy.logger || retryPolicyLogger; strategyLogger.info(`Retry ${retryCount}: Processing retry strategy ${strategy.name}.`); const modifiers = strategy.retry({ retryCount, response, responseError, }); if (modifiers.skipStrategy) { strategyLogger.info(`Retry ${retryCount}: Skipped.`); continue strategiesLoop; } const { errorToThrow, retryAfterInMs, redirectTo } = modifiers; if (errorToThrow) { strategyLogger.error(`Retry ${retryCount}: Retry strategy ${strategy.name} throws error:`, errorToThrow); throw errorToThrow; } if (retryAfterInMs || retryAfterInMs === 0) { strategyLogger.info(`Retry ${retryCount}: Retry strategy ${strategy.name} retries after ${retryAfterInMs}`); await delay(retryAfterInMs, undefined, { abortSignal: request.abortSignal }); continue retryRequest; } if (redirectTo) { strategyLogger.info(`Retry ${retryCount}: Retry strategy ${strategy.name} redirects to ${redirectTo}`); request.url = redirectTo; continue retryRequest; } } if (responseError) { logger.info(`None of the retry strategies could work with the received error. Throwing it.`); throw responseError; } if (response) { logger.info(`None of the retry strategies could work with the received response. Returning it.`); return response; } // If all the retries skip and there's no response, // we're still in the retry loop, so a new request will be sent // until `maxRetries` is reached. } }, }; } //# sourceMappingURL=retryPolicy.js.map