retry.js 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. var RetryOperation = require('./retry_operation');
  2. exports.operation = function(options) {
  3. var timeouts = exports.timeouts(options);
  4. return new RetryOperation(timeouts, {
  5. forever: options && options.forever,
  6. unref: options && options.unref
  7. });
  8. };
  9. exports.timeouts = function(options) {
  10. if (options instanceof Array) {
  11. return [].concat(options);
  12. }
  13. var opts = {
  14. retries: 10,
  15. factor: 2,
  16. minTimeout: 1 * 1000,
  17. maxTimeout: Infinity,
  18. randomize: false
  19. };
  20. for (var key in options) {
  21. opts[key] = options[key];
  22. }
  23. if (opts.minTimeout > opts.maxTimeout) {
  24. throw new Error('minTimeout is greater than maxTimeout');
  25. }
  26. var timeouts = [];
  27. for (var i = 0; i < opts.retries; i++) {
  28. timeouts.push(this.createTimeout(i, opts));
  29. }
  30. if (options && options.forever && !timeouts.length) {
  31. timeouts.push(this.createTimeout(i, opts));
  32. }
  33. // sort the array numerically ascending
  34. timeouts.sort(function(a,b) {
  35. return a - b;
  36. });
  37. return timeouts;
  38. };
  39. exports.createTimeout = function(attempt, opts) {
  40. var random = (opts.randomize)
  41. ? (Math.random() + 1)
  42. : 1;
  43. var timeout = Math.round(random * opts.minTimeout * Math.pow(opts.factor, attempt));
  44. timeout = Math.min(timeout, opts.maxTimeout);
  45. return timeout;
  46. };
  47. exports.wrap = function(obj, options, methods) {
  48. if (options instanceof Array) {
  49. methods = options;
  50. options = null;
  51. }
  52. if (!methods) {
  53. methods = [];
  54. for (var key in obj) {
  55. if (typeof obj[key] === 'function') {
  56. methods.push(key);
  57. }
  58. }
  59. }
  60. for (var i = 0; i < methods.length; i++) {
  61. var method = methods[i];
  62. var original = obj[method];
  63. obj[method] = function retryWrapper() {
  64. var op = exports.operation(options);
  65. var args = Array.prototype.slice.call(arguments);
  66. var callback = args.pop();
  67. args.push(function(err) {
  68. if (op.retry(err)) {
  69. return;
  70. }
  71. if (err) {
  72. arguments[0] = op.mainError();
  73. }
  74. callback.apply(this, arguments);
  75. });
  76. op.attempt(function() {
  77. original.apply(obj, args);
  78. });
  79. };
  80. obj[method].options = options;
  81. }
  82. };