-
Notifications
You must be signed in to change notification settings - Fork 107
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This option prevents the circuit from opening unless the number of requests during the statistical window exceeds this threshold. Fixes: #232
- Loading branch information
Showing
3 changed files
with
77 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ const HYSTRIX_STATS = Symbol('hystrix-stats'); | |
const CACHE = new WeakMap(); | ||
const ENABLED = Symbol('Enabled'); | ||
const WARMING_UP = Symbol('warming-up'); | ||
const VOLUME_THRESHOLD = Symbol('volume-threshold'); | ||
const deprecation = `options.maxFailures is deprecated. \ | ||
Please use options.errorThresholdPercentage`; | ||
|
||
|
@@ -65,6 +66,11 @@ Please use options.errorThresholdPercentage`; | |
* allow before enabling the circuit. This can help in situations where no matter | ||
* what your `errorThresholdPercentage` is, if the first execution times out or | ||
* fails, the circuit immediately opens. Default: 0 | ||
* @param options.volumeThreshold {Number} the minimum number of requests within | ||
* the rolling statistical window that must exist before the circuit breaker | ||
* can open. This is similar to `options.allowWarmUp` in that no matter how many | ||
* failures there are, if the number of requests within the statistical window | ||
* does not exceed this threshold, the circuit will remain closed. Default: 0 | ||
*/ | ||
class CircuitBreaker extends EventEmitter { | ||
constructor (action, options) { | ||
|
@@ -78,6 +84,7 @@ class CircuitBreaker extends EventEmitter { | |
|
||
this.semaphore = new Semaphore(this.options.capacity); | ||
|
||
this[VOLUME_THRESHOLD] = Number.isInteger(options.volumeThreshold) ? options.volumeThreshold : 0; | ||
this[WARMING_UP] = options.allowWarmUp === true; | ||
this[STATUS] = new Status(this.options); | ||
this[STATE] = CLOSED; | ||
|
@@ -246,6 +253,10 @@ class CircuitBreaker extends EventEmitter { | |
return this[WARMING_UP]; | ||
} | ||
|
||
get volumeThreshold () { | ||
return this[VOLUME_THRESHOLD]; | ||
} | ||
|
||
/** | ||
* Provide a fallback function for this {@link CircuitBreaker}. This | ||
* function will be executed when the circuit is `fire`d and fails. | ||
|
@@ -511,6 +522,7 @@ function fail (circuit, err, args, latency) { | |
|
||
// check stats to see if the circuit should be opened | ||
const stats = circuit.stats; | ||
if (stats.fires < circuit.volumeThreshold) return; | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
lance
Author
Member
|
||
const errorRate = stats.failures / stats.fires * 100; | ||
if (errorRate > circuit.options.errorThresholdPercentage || | ||
circuit.options.maxFailures >= stats.failures || | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
'use strict'; | ||
|
||
const test = require('tape'); | ||
const opossum = require('../'); | ||
const { passFail } = require('./common'); | ||
|
||
test('By default does not have a volume threshold', t => { | ||
t.plan(3); | ||
const options = { | ||
errorThresholdPercentage: 1, | ||
resetTimeout: 100 | ||
}; | ||
|
||
const breaker = opossum(passFail, options); | ||
breaker.fire(-1) | ||
.catch(e => t.equals(e, 'Error: -1 is < 0')) | ||
.then(() => { | ||
t.ok(breaker.opened, 'should be open after initial fire'); | ||
t.notOk(breaker.pendingClose, | ||
'should not be pending close after initial fire'); | ||
}); | ||
}); | ||
|
||
test('Has a volume threshold before tripping when option is provided', t => { | ||
t.plan(6); | ||
const options = { | ||
errorThresholdPercentage: 1, | ||
resetTimeout: 100, | ||
volumeThreshold: 3 | ||
}; | ||
|
||
const breaker = opossum(passFail, options); | ||
breaker.fire(-1) | ||
.then(t.fail) | ||
.catch(e => { | ||
t.notOk(breaker.opened, | ||
'should not be open before volume threshold has been reached'); | ||
t.notOk(breaker.pendingClose, | ||
'should not be pending close before volume threshold has been reached'); | ||
}) | ||
.then(_ => { | ||
breaker.fire(-1) | ||
.then(t.fail) | ||
.catch(e => { | ||
t.notOk(breaker.opened, | ||
'should not be open before volume threshold has been reached'); | ||
t.notOk(breaker.pendingClose, | ||
'should not be pending close before volume threshold has been reached'); | ||
}) | ||
.then(_ => { | ||
breaker.fire(-1) | ||
.catch(e => { | ||
t.equals(e, 'Error: -1 is < 0'); | ||
t.ok(breaker.opened, | ||
'should be open after volume threshold has been reached'); | ||
}) | ||
.then(t.end); | ||
}); | ||
}); | ||
}); |
I believe this line change has introduced a bug.
Steps to duplicate...
It seems like you shouldn't return early here if the circuit is halfOpen.