UNPKG

3.12 kBJavaScriptView Raw
1function RetryOperation(timeouts, options) {
2 // Compatibility for the old (timeouts, retryForever) signature
3 if (typeof options === 'boolean') {
4 options = { forever: options };
5 }
6
7 this._timeouts = timeouts;
8 this._options = options || {};
9 this._fn = null;
10 this._errors = [];
11 this._attempts = 1;
12 this._operationTimeout = null;
13 this._operationTimeoutCb = null;
14 this._timeout = null;
15
16 if (this._options.forever) {
17 this._cachedTimeouts = this._timeouts.slice(0);
18 }
19}
20module.exports = RetryOperation;
21
22RetryOperation.prototype.stop = function() {
23 if (this._timeout) {
24 clearTimeout(this._timeout);
25 }
26
27 this._timeouts = [];
28 this._cachedTimeouts = null;
29};
30
31RetryOperation.prototype.retry = function(err) {
32 if (this._timeout) {
33 clearTimeout(this._timeout);
34 }
35
36 if (!err) {
37 return false;
38 }
39
40 this._errors.push(err);
41
42 var timeout = this._timeouts.shift();
43 if (timeout === undefined) {
44 if (this._cachedTimeouts) {
45 // retry forever, only keep last error
46 this._errors.splice(this._errors.length - 1, this._errors.length);
47 this._timeouts = this._cachedTimeouts.slice(0);
48 timeout = this._timeouts.shift();
49 } else {
50 return false;
51 }
52 }
53
54 var self = this;
55 var timer = setTimeout(function() {
56 self._attempts++;
57
58 if (self._operationTimeoutCb) {
59 self._timeout = setTimeout(function() {
60 self._operationTimeoutCb(self._attempts);
61 }, self._operationTimeout);
62
63 if (this._options.unref) {
64 self._timeout.unref();
65 }
66 }
67
68 self._fn(self._attempts);
69 }, timeout);
70
71 if (this._options.unref) {
72 timer.unref();
73 }
74
75 return true;
76};
77
78RetryOperation.prototype.attempt = function(fn, timeoutOps) {
79 this._fn = fn;
80
81 if (timeoutOps) {
82 if (timeoutOps.timeout) {
83 this._operationTimeout = timeoutOps.timeout;
84 }
85 if (timeoutOps.cb) {
86 this._operationTimeoutCb = timeoutOps.cb;
87 }
88 }
89
90 var self = this;
91 if (this._operationTimeoutCb) {
92 this._timeout = setTimeout(function() {
93 self._operationTimeoutCb();
94 }, self._operationTimeout);
95 }
96
97 this._fn(this._attempts);
98};
99
100RetryOperation.prototype.try = function(fn) {
101 console.log('Using RetryOperation.try() is deprecated');
102 this.attempt(fn);
103};
104
105RetryOperation.prototype.start = function(fn) {
106 console.log('Using RetryOperation.start() is deprecated');
107 this.attempt(fn);
108};
109
110RetryOperation.prototype.start = RetryOperation.prototype.try;
111
112RetryOperation.prototype.errors = function() {
113 return this._errors;
114};
115
116RetryOperation.prototype.attempts = function() {
117 return this._attempts;
118};
119
120RetryOperation.prototype.mainError = function() {
121 if (this._errors.length === 0) {
122 return null;
123 }
124
125 var counts = {};
126 var mainError = null;
127 var mainErrorCount = 0;
128
129 for (var i = 0; i < this._errors.length; i++) {
130 var error = this._errors[i];
131 var message = error.message;
132 var count = (counts[message] || 0) + 1;
133
134 counts[message] = count;
135
136 if (count >= mainErrorCount) {
137 mainError = error;
138 mainErrorCount = count;
139 }
140 }
141
142 return mainError;
143};