retry.js 2.3 KB

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