index.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. 'use strict';
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.retryAsPromised = exports.TimeoutError = void 0;
  4. class TimeoutError extends Error {
  5. constructor(message, previousError) {
  6. super(message);
  7. this.name = "TimeoutError";
  8. this.previous = previousError;
  9. }
  10. }
  11. exports.TimeoutError = TimeoutError;
  12. function matches(match, err) {
  13. if (typeof match === 'function') {
  14. try {
  15. if (err instanceof match)
  16. return true;
  17. }
  18. catch (_) {
  19. return !!match(err);
  20. }
  21. }
  22. if (match === err.toString())
  23. return true;
  24. if (match === err.message)
  25. return true;
  26. return match instanceof RegExp
  27. && (match.test(err.message) || match.test(err.toString()));
  28. }
  29. function retryAsPromised(callback, optionsInput) {
  30. if (!callback || !optionsInput) {
  31. throw new Error('retry-as-promised must be passed a callback and a options set');
  32. }
  33. optionsInput = (typeof optionsInput === "number" ? { max: optionsInput } : optionsInput);
  34. const options = {
  35. $current: "$current" in optionsInput ? optionsInput.$current : 1,
  36. max: optionsInput.max,
  37. timeout: optionsInput.timeout || undefined,
  38. match: optionsInput.match ? Array.isArray(optionsInput.match) ? optionsInput.match : [optionsInput.match] : [],
  39. backoffBase: optionsInput.backoffBase === undefined ? 100 : optionsInput.backoffBase,
  40. backoffExponent: optionsInput.backoffExponent || 1.1,
  41. report: optionsInput.report,
  42. name: optionsInput.name || callback.name || 'unknown'
  43. };
  44. if (options.match && !Array.isArray(options.match))
  45. options.match = [options.match];
  46. if (options.report)
  47. options.report('Trying ' + options.name + ' #' + options.$current + ' at ' + new Date().toLocaleTimeString(), options);
  48. return new Promise(function (resolve, reject) {
  49. let timeout;
  50. let backoffTimeout;
  51. let lastError;
  52. if (options.timeout) {
  53. timeout = setTimeout(function () {
  54. if (backoffTimeout)
  55. clearTimeout(backoffTimeout);
  56. reject(new TimeoutError(options.name + ' timed out', lastError));
  57. }, options.timeout);
  58. }
  59. Promise.resolve(callback({ current: options.$current }))
  60. .then(resolve)
  61. .then(function () {
  62. if (timeout)
  63. clearTimeout(timeout);
  64. if (backoffTimeout)
  65. clearTimeout(backoffTimeout);
  66. })
  67. .catch(function (err) {
  68. if (timeout)
  69. clearTimeout(timeout);
  70. if (backoffTimeout)
  71. clearTimeout(backoffTimeout);
  72. lastError = err;
  73. if (options.report)
  74. options.report((err && err.toString()) || err, options, err);
  75. // Should not retry if max has been reached
  76. var shouldRetry = options.$current < options.max;
  77. if (!shouldRetry)
  78. return reject(err);
  79. shouldRetry = options.match.length === 0 || options.match.some(function (match) {
  80. return matches(match, err);
  81. });
  82. if (!shouldRetry)
  83. return reject(err);
  84. var retryDelay = options.backoffBase * Math.pow(options.backoffExponent, options.$current - 1);
  85. // Do some accounting
  86. options.$current++;
  87. if (options.report)
  88. options.report(`Retrying ${options.name} (${options.$current})`, options);
  89. if (retryDelay) {
  90. // Use backoff function to ease retry rate
  91. if (options.report)
  92. options.report(`Delaying retry of ${options.name} by ${retryDelay}`, options);
  93. backoffTimeout = setTimeout(function () {
  94. retryAsPromised(callback, options)
  95. .then(resolve)
  96. .catch(reject);
  97. }, retryDelay);
  98. }
  99. else {
  100. retryAsPromised(callback, options)
  101. .then(resolve)
  102. .catch(reject);
  103. }
  104. });
  105. });
  106. }
  107. exports.retryAsPromised = retryAsPromised;
  108. ;
  109. exports.default = retryAsPromised;