forked from STRML/node-toobusy
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtoobusy.js
94 lines (78 loc) · 2.75 KB
/
toobusy.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
var STANDARD_HIGHWATER = 70;
var STANDARD_INTERVAL = 500;
var STANDARD_DECAY_FACTOR = 3;
var STANDARD_MAX_VIOLATIONS = 0;
// decayFactor is a dampening factor. When determining average calls per second or
// current lag, we weigh the current value against the previous value using this factor to smooth spikes
var lastTime = new Date().valueOf(), now, lag, highWater = STANDARD_HIGHWATER, interval = STANDARD_INTERVAL, decayFactor = STANDARD_DECAY_FACTOR, maxViolations = STANDARD_MAX_VIOLATIONS, numViolations = 0, currentLag = 0;
var checkInterval = setInterval(function(){
now = new Date().valueOf();
lag = now - lastTime;
lag = (lag < interval) ? 0 : lag - interval;
currentLag = (lag + (currentLag * (decayFactor - 1))) / decayFactor;
lastTime = now;
if (currentLag > highWater) {
numViolations++;
} else {
numViolations = 0;
}
}, interval);
// Don't keep process open just for this timer.
checkInterval.unref();
var toobusy = function(){
if (numViolations <= maxViolations) {
return false;
}
// If current lag is < 2x the highwater mark, we don't always call it 'too busy'. E.g. with a 50ms lag
// and a 40ms highWater (1.25x highWater), 25% of the time we will block. With 80ms lag and a 40ms highWater,
// we will always block.
var pctToBlock = (currentLag - highWater) / highWater;
var rand = Math.random();
return rand < pctToBlock;
};
toobusy.lag = function(){
return parseInt(currentLag, 10);
};
toobusy.maxLag = function(newLag){
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.";
}
highWater = newLag;
return highWater;
};
toobusy.decayFactor = function(newDecay){
if(!newDecay) return decayFactor;
// If an arg was passed, try to set highWater.
if(Object.prototype.toString.call(newDecay) !== "[object Number]"){
throw "Expected numeric first argument.";
}
newDecay = parseInt(newDecay, 10);
if(newDecay <= 1){
throw "Decay factor should be greater than 1.";
}
decayFactor = newDecay;
return decayFactor;
};
toobusy.maxViolations = function(newViolations){
if(!newViolations) return maxViolations;
// If an arg was passed, try to set highWater.
if(Object.prototype.toString.call(newViolations) !== "[object Number]"){
throw "Expected numeric first argument.";
}
newViolations = parseInt(newViolations, 10);
if(newViolations <= 0){
throw "Max violations should be greater than 0.";
}
maxViolations = newViolations;
return maxViolations;
};
toobusy.shutdown = function(){
clearInterval(checkInterval);
};
module.exports = toobusy;