1 |
3a515b92
|
cagy
|
var RetryOperation = require('./retry_operation');
|
2 |
|
|
|
3 |
|
|
exports.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 |
|
|
|
12 |
|
|
exports.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 |
|
|
|
49 |
|
|
exports.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 |
|
|
|
60 |
|
|
exports.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 |
|
|
};
|