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