66 lines
2.1 KiB
JavaScript
66 lines
2.1 KiB
JavaScript
|
// Copyright (c) 2012 Mathieu Turcotte
|
||
|
// Licensed under the MIT license.
|
||
|
|
||
|
var events = require('events');
|
||
|
var precond = require('precond');
|
||
|
var util = require('util');
|
||
|
|
||
|
// A class to hold the state of a backoff operation. Accepts a backoff strategy
|
||
|
// to generate the backoff delays.
|
||
|
function Backoff(backoffStrategy) {
|
||
|
events.EventEmitter.call(this);
|
||
|
|
||
|
this.backoffStrategy_ = backoffStrategy;
|
||
|
this.maxNumberOfRetry_ = -1;
|
||
|
this.backoffNumber_ = 0;
|
||
|
this.backoffDelay_ = 0;
|
||
|
this.timeoutID_ = -1;
|
||
|
|
||
|
this.handlers = {
|
||
|
backoff: this.onBackoff_.bind(this)
|
||
|
};
|
||
|
}
|
||
|
util.inherits(Backoff, events.EventEmitter);
|
||
|
|
||
|
// Sets a limit, greater than 0, on the maximum number of backoffs. A 'fail'
|
||
|
// event will be emitted when the limit is reached.
|
||
|
Backoff.prototype.failAfter = function(maxNumberOfRetry) {
|
||
|
precond.checkArgument(maxNumberOfRetry > 0,
|
||
|
'Expected a maximum number of retry greater than 0 but got %s.',
|
||
|
maxNumberOfRetry);
|
||
|
|
||
|
this.maxNumberOfRetry_ = maxNumberOfRetry;
|
||
|
};
|
||
|
|
||
|
// Starts a backoff operation. Accepts an optional parameter to let the
|
||
|
// listeners know why the backoff operation was started.
|
||
|
Backoff.prototype.backoff = function(err) {
|
||
|
precond.checkState(this.timeoutID_ === -1, 'Backoff in progress.');
|
||
|
|
||
|
if (this.backoffNumber_ === this.maxNumberOfRetry_) {
|
||
|
this.emit('fail', err);
|
||
|
this.reset();
|
||
|
} else {
|
||
|
this.backoffDelay_ = this.backoffStrategy_.next();
|
||
|
this.timeoutID_ = setTimeout(this.handlers.backoff, this.backoffDelay_);
|
||
|
this.emit('backoff', this.backoffNumber_, this.backoffDelay_, err);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// Handles the backoff timeout completion.
|
||
|
Backoff.prototype.onBackoff_ = function() {
|
||
|
this.timeoutID_ = -1;
|
||
|
this.emit('ready', this.backoffNumber_, this.backoffDelay_);
|
||
|
this.backoffNumber_++;
|
||
|
};
|
||
|
|
||
|
// Stops any backoff operation and resets the backoff delay to its inital value.
|
||
|
Backoff.prototype.reset = function() {
|
||
|
this.backoffNumber_ = 0;
|
||
|
this.backoffStrategy_.reset();
|
||
|
clearTimeout(this.timeoutID_);
|
||
|
this.timeoutID_ = -1;
|
||
|
};
|
||
|
|
||
|
module.exports = Backoff;
|