exponentialRetryPolicy.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // Copyright (c) Microsoft Corporation. All rights reserved.
  2. // Licensed under the MIT License. See License.txt in the project root for license information.
  3. import * as tslib_1 from "tslib";
  4. import * as utils from "../util/utils";
  5. import { BaseRequestPolicy } from "./requestPolicy";
  6. import { RestError } from "../restError";
  7. export function exponentialRetryPolicy(retryCount, retryInterval, minRetryInterval, maxRetryInterval) {
  8. return {
  9. create: function (nextPolicy, options) {
  10. return new ExponentialRetryPolicy(nextPolicy, options, retryCount, retryInterval, minRetryInterval, maxRetryInterval);
  11. }
  12. };
  13. }
  14. var DEFAULT_CLIENT_RETRY_INTERVAL = 1000 * 30;
  15. var DEFAULT_CLIENT_RETRY_COUNT = 3;
  16. var DEFAULT_CLIENT_MAX_RETRY_INTERVAL = 1000 * 90;
  17. var DEFAULT_CLIENT_MIN_RETRY_INTERVAL = 1000 * 3;
  18. /**
  19. * @class
  20. * Instantiates a new "ExponentialRetryPolicyFilter" instance.
  21. */
  22. var ExponentialRetryPolicy = /** @class */ (function (_super) {
  23. tslib_1.__extends(ExponentialRetryPolicy, _super);
  24. /**
  25. * @constructor
  26. * @param {RequestPolicy} nextPolicy The next RequestPolicy in the pipeline chain.
  27. * @param {RequestPolicyOptions} options The options for this RequestPolicy.
  28. * @param {number} [retryCount] The client retry count.
  29. * @param {number} [retryInterval] The client retry interval, in milliseconds.
  30. * @param {number} [minRetryInterval] The minimum retry interval, in milliseconds.
  31. * @param {number} [maxRetryInterval] The maximum retry interval, in milliseconds.
  32. */
  33. function ExponentialRetryPolicy(nextPolicy, options, retryCount, retryInterval, minRetryInterval, maxRetryInterval) {
  34. var _this = _super.call(this, nextPolicy, options) || this;
  35. function isNumber(n) { return typeof n === "number"; }
  36. _this.retryCount = isNumber(retryCount) ? retryCount : DEFAULT_CLIENT_RETRY_COUNT;
  37. _this.retryInterval = isNumber(retryInterval) ? retryInterval : DEFAULT_CLIENT_RETRY_INTERVAL;
  38. _this.minRetryInterval = isNumber(minRetryInterval) ? minRetryInterval : DEFAULT_CLIENT_MIN_RETRY_INTERVAL;
  39. _this.maxRetryInterval = isNumber(maxRetryInterval) ? maxRetryInterval : DEFAULT_CLIENT_MAX_RETRY_INTERVAL;
  40. return _this;
  41. }
  42. ExponentialRetryPolicy.prototype.sendRequest = function (request) {
  43. var _this = this;
  44. return this._nextPolicy.sendRequest(request.clone())
  45. .then(function (response) { return retry(_this, request, response); })
  46. .catch(function (error) { return retry(_this, request, error.response, undefined, error); });
  47. };
  48. return ExponentialRetryPolicy;
  49. }(BaseRequestPolicy));
  50. export { ExponentialRetryPolicy };
  51. /**
  52. * Determines if the operation should be retried and how long to wait until the next retry.
  53. *
  54. * @param {ExponentialRetryPolicy} policy The ExponentialRetryPolicy that this function is being called against.
  55. * @param {number} statusCode The HTTP status code.
  56. * @param {RetryData} retryData The retry data.
  57. * @return {boolean} True if the operation qualifies for a retry; false otherwise.
  58. */
  59. function shouldRetry(policy, statusCode, retryData) {
  60. if (statusCode == undefined || (statusCode < 500 && statusCode !== 408) || statusCode === 501 || statusCode === 505) {
  61. return false;
  62. }
  63. var currentCount;
  64. if (!retryData) {
  65. throw new Error("retryData for the ExponentialRetryPolicyFilter cannot be null.");
  66. }
  67. else {
  68. currentCount = (retryData && retryData.retryCount);
  69. }
  70. return (currentCount < policy.retryCount);
  71. }
  72. /**
  73. * Updates the retry data for the next attempt.
  74. *
  75. * @param {ExponentialRetryPolicy} policy The ExponentialRetryPolicy that this function is being called against.
  76. * @param {RetryData} retryData The retry data.
  77. * @param {RetryError} [err] The operation"s error, if any.
  78. */
  79. function updateRetryData(policy, retryData, err) {
  80. if (!retryData) {
  81. retryData = {
  82. retryCount: 0,
  83. retryInterval: 0
  84. };
  85. }
  86. if (err) {
  87. if (retryData.error) {
  88. err.innerError = retryData.error;
  89. }
  90. retryData.error = err;
  91. }
  92. // Adjust retry count
  93. retryData.retryCount++;
  94. // Adjust retry interval
  95. var incrementDelta = Math.pow(2, retryData.retryCount) - 1;
  96. var boundedRandDelta = policy.retryInterval * 0.8 +
  97. Math.floor(Math.random() * (policy.retryInterval * 1.2 - policy.retryInterval * 0.8));
  98. incrementDelta *= boundedRandDelta;
  99. retryData.retryInterval = Math.min(policy.minRetryInterval + incrementDelta, policy.maxRetryInterval);
  100. return retryData;
  101. }
  102. function retry(policy, request, response, retryData, requestError) {
  103. retryData = updateRetryData(policy, retryData, requestError);
  104. var isAborted = request.abortSignal && request.abortSignal.aborted;
  105. if (!isAborted && shouldRetry(policy, response && response.status, retryData)) {
  106. return utils.delay(retryData.retryInterval)
  107. .then(function () { return policy._nextPolicy.sendRequest(request.clone()); })
  108. .then(function (res) { return retry(policy, request, res, retryData, undefined); })
  109. .catch(function (err) { return retry(policy, request, response, retryData, err); });
  110. }
  111. else if (isAborted || requestError || !response) {
  112. // If the operation failed in the end, return all errors instead of just the last one
  113. var err = retryData.error ||
  114. new RestError("Failed to send the request.", RestError.REQUEST_SEND_ERROR, response && response.status, response && response.request, response);
  115. return Promise.reject(err);
  116. }
  117. else {
  118. return Promise.resolve(response);
  119. }
  120. }
  121. //# sourceMappingURL=exponentialRetryPolicy.js.map