UNPKG

re

Version:
137 lines (109 loc) 3.67 kB
(function (){ // global on the server, window in the browser var root = this, previous_re = root.Re; Re.noConflict = function(){ root.Re = previous_re; return Re; }; // start actual code Re.STRATEGIES = {CONSTANT: 0, EXPONENTIAL: 1, LINEAR: 2}; var RETRIES_DEFAULT = 10, EXP_STRAT_DEFAULT = {"type": Re.STRATEGIES.EXPONENTIAL, "initial":100, "base":2}, CONST_STRAT_DEFAULT = {"type": Re.STRATEGIES.CONSTANT, "initial":400}, LINEAR_STRAT_DEFAULT = {"type": Re.STRATEGIES.LINEAR, "initial": 100}; Re.prototype.retryInterval; function Re(options){ if(!(this instanceof Re)) return new Re(options); var strategy; if(typeof options === "undefined") options = {}; if(typeof options.retries === "undefined") options.retries = RETRIES_DEFAULT; if(typeof options.strategy === "undefined") options.strategy = EXP_STRAT_DEFAULT; if(typeof options.strategy.type === "undefined") throw new TypeError("Invalid retry strategy"); strategy = options.strategy; this.retry = 0; this.timeout = options.timeout; this.maxRetries = options.retries; switch(options.strategy.type){ case Re.STRATEGIES.CONSTANT: if(typeof strategy.initial === "undefined") strategy.initial = CONST_STRAT_DEFAULT.initial; this.retryInterval = createConstantRetry(strategy); break; case Re.STRATEGIES.EXPONENTIAL: if(typeof strategy.initial === "undefined") strategy.initial = EXP_STRAT_DEFAULT.initial; if(typeof strategy.base === "undefined") strategy.base = EXP_STRAT_DEFAULT.base; this.retryInterval = createExponentialRetry(strategy); break; case Re.STRATEGIES.LINEAR: if(typeof strategy.initial === "undefined") strategy.initial = LINEAR_STRAT_DEFAULT.initial; this.retryInterval = createLinearRetry(strategy); break; default: throw new TypeError("Invalid retry strategy"); break; } }; Re.prototype.try = function(operation, callback){ var done = this.createDoneCallback(operation, callback, this.try); try{ operation(this.retry, done); } catch(err) { done(err); } }; Re.prototype.do = function(operation, callback){ var done = this.createDoneCallback(operation, callback, this.do); operation(this.retry, done); }; Re.prototype.createDoneCallback = function(operation, callback, method){ var self = this; return function(err){ var doneArguments = arguments; callback = callback || function () {}; if(!err) return setTimeout(function(){callback.apply(null, doneArguments);}, 0); if(self.retry < self.maxRetries){ setTimeout(function(){ method.call(self, operation, callback); }, self.retryInterval(self.retry)); } else { return setTimeout(function(){callback.apply(null, doneArguments);}, 0); } self.retry++; }; }; function createExponentialRetry(spec){ return function(retries){ var spread = spec.rand ? Math.random() + 1 : 1, initial = spec.initial, base = spec.base, max = spec.max, full = spread * initial * Math.pow(base, retries); return max ? Math.min(full, max) : full; }; }; function createLinearRetry(spec){ return function(retries){ var spread = spec.rand ? Math.random() + 1 : 1, initial = spec.initial, max = spec.max, full = spread*initial*(retries+1); return max ? Math.min(full, max) : full; }; }; function createConstantRetry(spec){ return function(){ var spread = spec.rand ? Math.random() + 1 : 1, initial = spec.initial; return spread*initial; }; }; // Node.js if(typeof module !== 'undefined' && module.exports){ module.exports = Re; } // included directly via <script> tag else { root.Re = Re; } }());