File: include/error/errors_over_time.js
/*
Copyright (C) 2016 PencilBlue, LLC
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
'use strict';
module.exports = function ErrorsOverTimeModule(/*pb*/) {
/**
* Wraps up code that allows developers the ability to time box errors. In
* some instances errors will occur. It is only when a certain number of those
* errors occur within a given time span that it is recognized that recovery is
* improbable. When the threshold is broken the code allows you to throw an
* error that represents all others that contributed to the threshold breach.
* @class ErrorsOverTime
* @constructor
* @param {Integer} errorSpan The upper bound on the number of errors that can
* occur within the provided time frame before it is determined that recovery
* is not possible.
* @param {Integer} errorThreshold The upper bound on the amount of time, in
* milliseconds, that errors can occur in before it is determined that recovery
* is not possible.
* @param {String} [prefix] The prefix to any error message that is generated
* by the instance
*/
function ErrorsOverTime(errorSpan, errorThreshold, prefix) {
/**
* The upper bound on the number of errors that can occur within the provided
* time frame before it is determined that recovery is not possible.
* @property errorSpan
* @type {Integer}
*/
this.errorSpan = errorSpan;
/**
* The upper bound on the amount of time, in milliseconds, that errors can
* occur in before it is determined that recovery is not possible.
* @property errorThreshold
* @type {Integer}
*/
this.errorThreshold = errorThreshold;
/**
* The list of errors that will be used to determin if too many errors have
* occurred within a given time frame.
* @property errors
* @type {Array}
*/
this.errors = [];
/**
* The total number of errors that have occurred
* @property totalErrorCnt
* @type {Integer}
*/
this.totalErrorCnt = 0;
/**
* The prefix to any error message that is generated by the instance
* @property prefix
* @type {String}
*/
this.prefix = prefix;
}
/**
* Adds an error into the calculation to determine if too many errors have
* occurred within a particular time span. If the threshold has been broken an
* error is thrown.
* @method throwIfOutOfBounds
* @param {Error} The error that occurred
* @param {String} prefix The error message text that will come first
* @return {Boolean} TRUE if threshold is in tact, FALSE if not
*/
ErrorsOverTime.prototype.throwIfOutOfBounds = function(err, prefix) {
if (!this.errorOccurred(err)) {
ErrorsOverTime.generateError(this.errors, prefix || this.prefix);
}
return true;
};
/**
* Adds an error into the calculation to determine if too many errors have
* occurred within a particular time span.
* @method errorOccurred
* @param {Error} The error that occurred
* @return {Boolean} TRUE if threshold is in tact, FALSE if not
*/
ErrorsOverTime.prototype.errorOccurred = function(err) {
//add the error
this.totalErrorCnt++;
this.errors.push(err);
//shave off any errors that are outside of our span
if (this.errors.length > this.errorSpan) {
this.errors.splice(0, 1);
}
return this.isWithinLimits();
};
/**
* Determines if the errors that have occurred are within the acceptable tolerance.
* @method isWithinLimits
* @return {Boolean} TRUE if threshold in tact, FALSE if not
*/
ErrorsOverTime.prototype.isWithinLimits = function() {
var withinLimits = true;
if (this.errors.length >= this.errorSpan) {
withinLimits = this.getRange() > this.errorThreshold;
}
return withinLimits;
};
/**
* Gets the time span over which the current set of errors has occurred
* @method getRange
* @return {Integer} The number of milliseconds over which the last "n" number
* of errors have occurred where "n" is the value is between 0 and the value of
* the errorSpan property inclusive.
*/
ErrorsOverTime.prototype.getRange = function() {
return this.errors[this.errors.length - 1] - this.errors[this.errors.length - this.errorSpan];
};
/**
* Generates and throws an Error that represents all of the errors that
* triggered the threshold breach.
* @static
* @method generateError
* @param {Array} errors The array of errors that will be represented by one
* wrapper error
* @param {String} prefix The error message text that will come first
*/
ErrorsOverTime.generateError = function(errors, prefix) {
throw ErrorsOverTime.createError(errors, prefix);
};
/**
* Creates an Error that represents all of the errors that triggered the
* threshold breach.
* @static
* @method createError
* @param {Array} errors The array of errors that will be represented by one
* wrapper error
* @param {String} prefix The error message text that will come first
* @return {Error}
*/
ErrorsOverTime.createError = function(errors, prefix) {
if (!prefix) {
prefix = '';
}
var pattern = prefix + 'Threshold breached by:';
errors.forEach(function(errItem) {
pattern += '\n' + errItem.stack;
});
pattern += '\n----------------------------------------';
return new Error(pattern);
};
return ErrorsOverTime;
};