toobusy-js
Advanced tools
Comparing version 0.3.1 to 0.4.0
@@ -5,8 +5,8 @@ { | ||
"homepage": "https://github.com/STRML/node-toobusy", | ||
"version": "0.3.1", | ||
"dependencies": { | ||
}, | ||
"version": "0.4.0", | ||
"dependencies": {}, | ||
"devDependencies": { | ||
"should": "1.2.1", | ||
"mocha": "1.7.0" | ||
"mocha": "1.7.0", | ||
"pre-commit": "^1.0.5", | ||
"should": "1.2.1" | ||
}, | ||
@@ -13,0 +13,0 @@ "maintainers": [ |
@@ -43,5 +43,5 @@ # Is Your Node Process Too Busy? | ||
express = require('express'); | ||
var app = express(); | ||
// middleware which blocks requests when we're too busy | ||
@@ -53,5 +53,5 @@ app.use(function(req, res, next) { | ||
next(); | ||
} | ||
} | ||
}); | ||
app.get('/', function(req, res) { | ||
@@ -63,5 +63,5 @@ // processing the request requires some work! | ||
}); | ||
var server = app.listen(3000); | ||
process.on('SIGINT', function() { | ||
@@ -83,3 +83,4 @@ server.close(); | ||
// set maximum lag to an aggressive value | ||
require('toobusy-js').maxLag(10); | ||
var toobusy = require('toobusy-js'); | ||
toobusy.maxLag(10); | ||
``` | ||
@@ -86,0 +87,0 @@ |
51
tests.js
@@ -1,11 +0,14 @@ | ||
const | ||
should = require('should'), | ||
toobusy = require('./'); | ||
'use strict'; | ||
var should = require('should'); | ||
var toobusy = require('./'); | ||
/*global describe, it, beforeEach, afterEach */ | ||
describe('the library', function() { | ||
it('should export a couple functions', function(done) { | ||
it('should export a couple functions', function() { | ||
(toobusy).should.be.a('function'); | ||
(toobusy.maxLag).should.be.a('function'); | ||
(toobusy.shutdown).should.be.a('function'); | ||
done(); | ||
(toobusy.interval).should.be.a('function'); | ||
(toobusy.shutdown).should.be.a('function'); | ||
(toobusy).should.not.have.property('start'); | ||
}); | ||
@@ -15,19 +18,41 @@ }); | ||
describe('maxLag', function() { | ||
it('should default to 70', function(done) { | ||
it('should default to 70', function() { | ||
(toobusy.maxLag()).should.equal(70); | ||
done(); | ||
}); | ||
it('should throw an exception for values < 10', function(done) { | ||
it('should throw an exception for values < 10', function() { | ||
(function() { toobusy.maxLag(9); }).should.throw; | ||
done(); | ||
}); | ||
it('should be configurable', function(done) { | ||
it('should be configurable', function() { | ||
(toobusy.maxLag(50)).should.equal(50); | ||
(toobusy.maxLag(10)).should.equal(10); | ||
(toobusy.maxLag()).should.equal(10); | ||
done(); | ||
}); | ||
}); | ||
describe('interval', function() { | ||
it('should default to 500', function() { | ||
(toobusy.interval()).should.equal(500); | ||
}); | ||
it('should throw an exception for values < 16', function() { | ||
(function() { toobusy.interval(15); }).should.throw; | ||
}); | ||
it('should be configurable', function() { | ||
(toobusy.interval(250)).should.equal(250); | ||
(toobusy.interval(300)).should.equal(300); | ||
(toobusy.interval()).should.equal(300); | ||
}); | ||
}); | ||
describe('toobusy()', function() { | ||
// Set lower thresholds for each of these tests. | ||
// Resetting the interval() also resets the internal lag counter, which | ||
// is nice for making these tests independent of each other. | ||
beforeEach(function() { | ||
toobusy.maxLag(10); | ||
toobusy.interval(250); | ||
}); | ||
afterEach(function() { | ||
toobusy.maxLag(70); | ||
toobusy.interval(500); | ||
}); | ||
it('should return true after a little load', function(done) { | ||
@@ -37,3 +62,3 @@ function load() { | ||
var start = new Date(); | ||
while ((new Date() - start) < 250) { | ||
while ((new Date() - start) < 100) { | ||
for (var i = 0; i < 1e5;) i++; | ||
@@ -55,3 +80,3 @@ } | ||
var start = new Date(); | ||
while ((new Date() - start) < 250) { | ||
while ((new Date() - start) < 100) { | ||
for (var i = 0; i < 1e5;) i++; | ||
@@ -58,0 +83,0 @@ } |
105
toobusy.js
@@ -1,4 +0,6 @@ | ||
var setInterval = require("timers").setInterval; | ||
var clearInterval = require("timers").clearInterval; | ||
'use strict'; | ||
// | ||
// Constants | ||
// | ||
var STANDARD_HIGHWATER = 70; | ||
@@ -12,15 +14,17 @@ var STANDARD_INTERVAL = 500; | ||
var lastTime = new Date().valueOf(), now, lag, highWater = STANDARD_HIGHWATER, interval = STANDARD_INTERVAL, currentLag = 0; | ||
// | ||
// Vars | ||
// | ||
var checkInterval = setInterval(function(){ | ||
now = new Date().valueOf(); | ||
lag = now - lastTime; | ||
lag = (lag < interval) ? 0 : lag - interval; | ||
currentLag = (lag + (currentLag * (AVG_DECAY_FACTOR - 1))) / AVG_DECAY_FACTOR; | ||
lastTime = now; | ||
}, interval); | ||
var lastTime = new Date().valueOf(); | ||
var highWater = STANDARD_HIGHWATER; | ||
var interval = STANDARD_INTERVAL; | ||
var currentLag = 0; | ||
var checkInterval; | ||
// Don't keep process open just for this timer. | ||
checkInterval.unref(); | ||
/** | ||
* Main export function. | ||
* @return {Boolean} True if node process is too busy. | ||
*/ | ||
var toobusy = function(){ | ||
@@ -31,10 +35,44 @@ // If current lag is < 2x the highwater mark, we don't always call it 'too busy'. E.g. with a 50ms lag | ||
var pctToBlock = (currentLag - highWater) / highWater; | ||
var rand = Math.random(); | ||
return rand < pctToBlock; | ||
return Math.random() < pctToBlock; | ||
}; | ||
/** | ||
* Sets or gets the current check interval. | ||
* If you want more sensitive checking, set a faster (lower) interval. A lower maxLag can also create a more | ||
* sensitive check. | ||
* @param {Number} [newInterval] New interval to set. If not provided, will return the existing interval. | ||
* @return {Number} New or existing interval. | ||
*/ | ||
toobusy.interval = function(newInterval) { | ||
if (!newInterval) return interval; | ||
if (typeof newInterval !== "number") throw new Error("Interval must be a number."); | ||
newInterval = Math.round(newInterval); | ||
if(newInterval < 16) throw new Error("Maximum lag should be greater than 16ms."); | ||
toobusy.shutdown(); | ||
interval = newInterval; | ||
start(); | ||
return interval; | ||
}; | ||
/** | ||
* Returns last lag reading from last check interval. | ||
* @return {Number} Lag in ms. | ||
*/ | ||
toobusy.lag = function(){ | ||
return parseInt(currentLag, 10); | ||
return Math.round(currentLag); | ||
}; | ||
/** | ||
* Set or get the current max latency threshold. Default is 70ms. | ||
* | ||
* Note that if event loop lag goes over this threshold, the process is not always 'too busy' - the farther | ||
* it goes over the threshold, the more likely the process will be considered too busy. | ||
* | ||
* The percentage is equal to the percent over the max lag threshold. So 1.25x over the maxLag will indicate | ||
* too busy 25% of the time. 2x over the maxLag threshold will indicate too busy 100% of the time. | ||
* @param {Number} [newLag] New maxLag (highwater) threshold. | ||
* @return {Number} New or existing maxLag (highwater) threshold. | ||
*/ | ||
toobusy.maxLag = function(newLag){ | ||
@@ -44,9 +82,6 @@ if(!newLag) return highWater; | ||
// If an arg was passed, try to set highWater. | ||
if(Object.prototype.toString.call(newLag) !== "[object Number]"){ | ||
throw "Expected numeric first argument."; | ||
} | ||
newLag = parseInt(newLag, 10); | ||
if(newLag < 10){ | ||
throw "Maximum lag should be greater than 10ms."; | ||
} | ||
if (typeof interval !== "number") throw new Error("MaxLag must be a number."); | ||
newLag = Math.round(newLag); | ||
if(newLag < 10) throw new Error("Maximum lag should be greater than 10ms."); | ||
highWater = newLag; | ||
@@ -56,6 +91,30 @@ return highWater; | ||
/** | ||
* Shuts down toobusy. | ||
* | ||
* Not necessary to call this manually, only do this if you know what you're doing. `unref()` is called | ||
* on toobusy's check interval, so it will never keep the server open. | ||
*/ | ||
toobusy.shutdown = function(){ | ||
currentLag = 0; | ||
clearInterval(checkInterval); | ||
}; | ||
module.exports = toobusy; | ||
/** | ||
* Private - starts checking lag. | ||
*/ | ||
function start() { | ||
checkInterval = setInterval(function(){ | ||
var now = Date.now(); | ||
var lag = now - lastTime; | ||
lag = Math.max(0, lag - interval); | ||
// Dampen lag. See AVG_DECAY_FACTOR initialization at the top of this file. | ||
currentLag = (lag + (currentLag * (AVG_DECAY_FACTOR - 1))) / AVG_DECAY_FACTOR; | ||
lastTime = now; | ||
}, interval); | ||
// Don't keep process open just for this timer. | ||
checkInterval.unref(); | ||
} | ||
module.exports = toobusy; |
14770
314
107
3