index.js 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. 'use strict';
  2. const retry = require('retry');
  3. class AbortError extends Error {
  4. constructor(message) {
  5. super();
  6. if (message instanceof Error) {
  7. this.originalError = message;
  8. ({message} = message);
  9. } else {
  10. this.originalError = new Error(message);
  11. this.originalError.stack = this.stack;
  12. }
  13. this.name = 'AbortError';
  14. this.message = message;
  15. }
  16. }
  17. function decorateErrorWithCounts(error, attemptNumber, options) {
  18. // Minus 1 from attemptNumber because the first attempt does not count as a retry
  19. const retriesLeft = options.retries - (attemptNumber - 1);
  20. error.attemptNumber = attemptNumber;
  21. error.retriesLeft = retriesLeft;
  22. return error;
  23. }
  24. module.exports = (input, options) => new Promise((resolve, reject) => {
  25. options = Object.assign({
  26. onFailedAttempt: () => {},
  27. retries: 10
  28. }, options);
  29. const operation = retry.operation(options);
  30. operation.attempt(attemptNumber => Promise.resolve(attemptNumber)
  31. .then(input)
  32. .then(resolve, error => {
  33. if (error instanceof AbortError) {
  34. operation.stop();
  35. reject(error.originalError);
  36. } else if (error instanceof TypeError) {
  37. operation.stop();
  38. reject(error);
  39. } else if (operation.retry(error)) {
  40. decorateErrorWithCounts(error, attemptNumber, options);
  41. options.onFailedAttempt(error);
  42. } else {
  43. decorateErrorWithCounts(error, attemptNumber, options);
  44. options.onFailedAttempt(error);
  45. reject(operation.mainError());
  46. }
  47. })
  48. );
  49. });
  50. module.exports.AbortError = AbortError;