Comparing version 3.0.0 to 4.0.0
@@ -5,2 +5,11 @@ # Changelog | ||
## [4.0.0](https://github.com/nodeshift/opossum/compare/v3.1.0...v4.0.0) (2019-08-21) | ||
## [3.1.0](https://github.com/nodeshift/opossum/compare/v3.0.0...v3.1.0) (2019-08-21) | ||
### Features | ||
* refactor Prometheus and Hystrix metrics ([#350](https://github.com/nodeshift/opossum/issues/350)) ([3adbb90](https://github.com/nodeshift/opossum/commit/3adbb90)) | ||
## [3.0.0](https://github.com/nodeshift/opossum/compare/v2.3.0...v3.0.0) (2019-07-26) | ||
@@ -7,0 +16,0 @@ |
105
index.js
'use strict'; | ||
const CircuitBreaker = require('./lib/circuit'); | ||
let lastCircuit; | ||
const defaults = { | ||
timeout: 10000, // 10 seconds | ||
errorThresholdPercentage: 50, | ||
resetTimeout: 30000 // 30 seconds | ||
}; | ||
/** | ||
* Creates a {@link CircuitBreaker} instance capable of executing `action`. | ||
* | ||
* @param {Function} action The action to fire for this {@link CircuitBreaker} | ||
* @param {Object} options Options for the {@link CircuitBreaker} | ||
* @param {Number} options.timeout The time in milliseconds that action should | ||
* be allowed to execute before timing out. Default 10000 (10 seconds) | ||
* @param {Number} options.maxFailures (Deprecated) The number of times the | ||
* circuit can fail before opening. Default 10. | ||
* @param {Number} options.resetTimeout The time in milliseconds to wait before | ||
* setting the breaker to `halfOpen` state, and trying the action again. | ||
* Default: 30000 (30 seconds) | ||
* @param {Number} options.rollingCountTimeout Sets the duration of the | ||
* statistical rolling window, in milliseconds. This is how long Opossum keeps | ||
* metrics for the circuit breaker to use and for publishing. Default: 10000 | ||
* @param {Number} options.rollingCountBuckets Sets the number of buckets the | ||
* rolling statistical window is divided into. So, if | ||
* options.rollingCountTimeout is 10000, and options.rollingCountBuckets is 10, | ||
* then the statistical window will be 1000 1 second snapshots in the | ||
* statistical window. Default: 10 | ||
* @param {String} options.name the circuit name to use when reporting stats. | ||
* Default: the name of the function this circuit controls. | ||
* @param {boolean} options.rollingPercentilesEnabled This property indicates | ||
* whether execution latencies should be tracked and calculated as percentiles. | ||
* If they are disabled, all summary statistics (mean, percentiles) are | ||
* returned as -1. Default: false | ||
* @param {Number} options.capacity the number of concurrent requests allowed. | ||
* If the number currently executing function calls is equal to | ||
* options.capacity, further calls to `fire()` are rejected until at least one | ||
* of the current requests completes. Default: `Number.MAX_SAFE_INTEGER`. | ||
* @param {Number} options.errorThresholdPercentage the error percentage at | ||
* which to open the circuit and start short-circuiting requests to fallback. | ||
* Default: 50 | ||
* @param {boolean} options.enabled whether this circuit is enabled upon | ||
* construction. Default: true | ||
* @param {boolean} options.allowWarmUp determines whether to allow failures | ||
* without opening the circuit during a brief warmup period (this is the | ||
* `rollingCountDuration` property). Default: false | ||
* 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 {Number} options.volumeThreshold 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 | ||
* @param {Function} options.errorFilter an optional function that will be | ||
* called when the circuit's function fails (returns a rejected Promise). If | ||
* this function returns truthy, the circuit's failure statistics will not be | ||
* incremented. This is useful, for example, when you don't want HTTP 404 to | ||
* trip the circuit, but still want to handle it as a failure case. | ||
* @return {CircuitBreaker} a newly created {@link CircuitBreaker} instance | ||
*/ | ||
function factory (action, options) { | ||
lastCircuit = new CircuitBreaker(action, | ||
Object.assign({}, defaults, options)); | ||
return lastCircuit; | ||
} | ||
/** | ||
* Get the Prometheus metrics for all circuits. | ||
* @function factory.metrics | ||
* @return {String} the metrics for all circuits or | ||
* undefined if no circuits have been created | ||
*/ | ||
factory.metrics = function metrics() { | ||
// Just get the metrics for the last circuit that was created | ||
// since prom-client is additive | ||
if (lastCircuit && lastCircuit.metrics) return lastCircuit.metrics.metrics; | ||
} | ||
let warningIssued = false; | ||
Object.defineProperty(factory, 'stats', { | ||
get: _ => { | ||
if (!warningIssued) { | ||
warningIssued = true; | ||
console.warn(`WARNING: Hystrics stats are deprecated | ||
See: https://github.com/Netflix/Hystrix#dashboard`) | ||
} | ||
return require('./lib/hystrix-stats').stream; | ||
} | ||
}); | ||
/** | ||
* Get an <code>Iterator</code> object containing all | ||
* circuits that have been created but not subsequently shut down. | ||
* @function factory.circuits | ||
* @return {Iterator} an <code>Iterator</code> of all available circuits | ||
*/ | ||
factory.circuits = CircuitBreaker.circuits; | ||
module.exports = exports = factory; | ||
// Allow use of default import syntax in TypeScript | ||
module.exports.default = factory; | ||
module.exports = exports = require('./lib/circuit'); |
@@ -5,8 +5,3 @@ 'use strict'; | ||
const Status = require('./status'); | ||
const HystrixStats = require('./hystrix-stats'); | ||
const Semaphore = require('./semaphore'); | ||
let PrometheusMetrics; | ||
if (!process.env.WEB) { | ||
PrometheusMetrics = require('./prometheus-metrics'); | ||
} | ||
@@ -23,4 +18,2 @@ const STATE = Symbol('state'); | ||
const GROUP = Symbol('group'); | ||
const HYSTRIX_STATS = Symbol('hystrix-stats'); | ||
const PROMETHEUS_METRICS = Symbol('prometheus-metrics'); | ||
const CACHE = new WeakMap(); | ||
@@ -32,7 +25,3 @@ const ENABLED = Symbol('Enabled'); | ||
Please use options.errorThresholdPercentage`; | ||
const CIRCUITS = new Set(); | ||
let warningIssued = false; | ||
/** | ||
@@ -88,3 +77,3 @@ * Constructs a {@link CircuitBreaker}. | ||
* called when the circuit's function fails (returns a rejected Promise). If | ||
* this function returns truthy, the circuit's failure statistics will not be | ||
* this function returns truthy, the circuit's failPure statistics will not be | ||
* incremented. This is useful, for example, when you don't want HTTP 404 to | ||
@@ -108,5 +97,9 @@ * trip the circuit, but still want to handle it as a failure case. | ||
class CircuitBreaker extends EventEmitter { | ||
constructor (action, options) { | ||
constructor (action, options = {}) { | ||
super(); | ||
this.options = options; | ||
this.options.timeout = options.timeout || 10000; | ||
this.options.resetTimeout = options.resetTimeout || 30000; | ||
this.options.errorThresholdPercentage = | ||
options.errorThresholdPercentage || 50; | ||
this.options.rollingCountTimeout = options.rollingCountTimeout || 10000; | ||
@@ -189,14 +182,2 @@ this.options.rollingCountBuckets = options.rollingCountBuckets || 10; | ||
} | ||
// Register with the hystrix stats listener | ||
this[HYSTRIX_STATS] = new HystrixStats(this); | ||
// Add Prometheus metrics if not running in a web env | ||
if (PrometheusMetrics && options.usePrometheus) { | ||
this[PROMETHEUS_METRICS] = new PrometheusMetrics( | ||
this, | ||
options.prometheusRegistry | ||
); | ||
} | ||
CIRCUITS.add(this); | ||
} | ||
@@ -250,6 +231,8 @@ | ||
this.status.shutdown(); | ||
this.hystrixStats.shutdown(); | ||
this.metrics && this.metrics.clear(); | ||
this[STATE] = SHUTDOWN; | ||
CIRCUITS.delete(this); | ||
/** | ||
* Emitted when the circuit breaker has been shut down. | ||
* @event CircuitBreaker#shutdown | ||
*/ | ||
this.emit('shutdown'); | ||
} | ||
@@ -331,23 +314,2 @@ | ||
/** | ||
* Get the hystrixStats. | ||
* @type {HystrixStats} | ||
*/ | ||
get hystrixStats () { | ||
if (!warningIssued) { | ||
warningIssued = true; | ||
console.warn(`WARNING: Hystrics stats are deprecated | ||
See: https://github.com/Netflix/Hystrix#dashboard`) | ||
} | ||
return this[HYSTRIX_STATS]; | ||
} | ||
/** | ||
* Get the prometheus metrics for this circuit | ||
* @type {PrometheusMetrics} | ||
*/ | ||
get metrics () { | ||
return this[PROMETHEUS_METRICS]; | ||
} | ||
/** | ||
* Gets whether the circuit is enabled or not | ||
@@ -677,13 +639,2 @@ * @type {Boolean} | ||
/** | ||
* Gets a Set iterator of all active circuits. If a circuit | ||
* has been created, but subsequently shut down, it will not | ||
* be included in the Set iterator. | ||
* | ||
* @returns {Iterator} an Iterator object containing a reference | ||
* to all {CircuitBreaker} instances that have been created. | ||
*/ | ||
CircuitBreaker.circuits = function circuits() { | ||
return CIRCUITS.values(); | ||
} | ||
module.exports = exports = CircuitBreaker; |
@@ -9,3 +9,3 @@ 'use strict'; | ||
let sem = { | ||
const sem = { | ||
take, | ||
@@ -12,0 +12,0 @@ release, |
{ | ||
"name": "opossum", | ||
"version": "3.0.0", | ||
"version": "4.0.0", | ||
"author": "Red Hat, Inc.", | ||
@@ -59,7 +59,7 @@ "license": "Apache-2.0", | ||
"serve": "^11.0.0", | ||
"standard-version": "6.0.1", | ||
"standardx": "^3.0.1", | ||
"standard-version": "7.0.0", | ||
"standardx": "^5.0.0", | ||
"tap-spec": "~5.0.0", | ||
"tape": "~4.11.0", | ||
"webpack": "~4.38.0", | ||
"webpack": "~4.39.0", | ||
"webpack-cli": "~3.3.0" | ||
@@ -77,5 +77,3 @@ }, | ||
], | ||
"dependencies": { | ||
"prom-client": "^11.2.1" | ||
} | ||
"dependencies": {} | ||
} |
@@ -36,3 +36,3 @@ # opossum [![CircleCI](https://circleci.com/gh/nodeshift/opossum/tree/master.svg?style=svg&circle-token=0742302baa8c95cef354997ea52a383d3d078ff1)](https://circleci.com/gh/nodeshift/opossum/tree/master) | ||
```javascript | ||
const circuitBreaker = require('opossum'); | ||
const CircuitBreaker = require('opossum'); | ||
@@ -50,3 +50,3 @@ function asyncFunctionThatCouldFail (x, y) { | ||
}; | ||
const breaker = circuitBreaker(asyncFunctionThatCouldFail, options); | ||
const breaker = new CircuitBreaker(asyncFunctionThatCouldFail, options); | ||
@@ -65,3 +65,3 @@ breaker.fire(params) | ||
```javascript | ||
const breaker = circuitBreaker(asyncFunctionThatCouldFail, options); | ||
const breaker = new CircuitBreaker(asyncFunctionThatCouldFail, options); | ||
// if asyncFunctionThatCouldFail starts to fail, firing the breaker | ||
@@ -130,3 +130,3 @@ // will trigger our fallback function | ||
``` | ||
In the browser's global scope will be a `circuitBreaker` function. Use it | ||
In the browser's global scope will be a `CircuitBreaker` constructor. Use it | ||
to create circuit breakers, guarding against network failures in your REST | ||
@@ -144,3 +144,3 @@ API calls. | ||
const circuit = circuitBreaker(() => $.get(route), circuitBreakerOptions); | ||
const circuit = new CircuitBreaker(() => $.get(route), circuitBreakerOptions); | ||
circuit.fallback(() => `${route} unavailable right now. Try later.`)); | ||
@@ -175,3 +175,3 @@ circuit.on('success', (result) => $(element).append(JSON.stringify(result)})); | ||
```js | ||
const circuit = circuitBreaker(() => $.get(route), circuitBreakerOptions); | ||
const circuit = new CircuitBreaker(() => $.get(route), circuitBreakerOptions); | ||
@@ -220,6 +220,6 @@ circuit.fallback(() => ({ body: `${route} unavailable right now. Try later.` })); | ||
const { promisify } = require('util'); | ||
const circuitBreaker = require('opossum'); | ||
const CircuitBreaker = require('opossum'); | ||
const readFile = promisify(fs.readFile); | ||
const breaker = circuitBreaker(readFile, options); | ||
const breaker = new CircuitBreaker(readFile, options); | ||
@@ -235,3 +235,3 @@ breaker.fire('./package.json', 'utf-8') | ||
```javascript | ||
const breaker = circuitBreaker('foo', options); | ||
const breaker = new CircuitBreaker('foo', options); | ||
@@ -252,52 +252,12 @@ breaker.fire() | ||
#### Prometheus | ||
Provide `{ usePrometheus: true }` in the options when creating a circuit to produce | ||
metrics that are consumable by Prometheus. These metrics include information about | ||
the circuit itself, for example how many times it has opened, as well as general Node.js | ||
statistics, for example event loop lag. To get consolidated metrics for all circuits in your | ||
application, use the `metrics()` function on the factory. | ||
The [`opossum-prometheus`](https://github.com/nodeshift/opossum-prometheus) module | ||
can be used to produce metrics that are consumable by Prometheus. | ||
These metrics include information about the circuit itself, for example how many | ||
times it has opened, as well as general Node.js statistics, for example event loop lag. | ||
```js | ||
const opossum = require('opossum'); | ||
// create a circuit | ||
const circuit = opossum(functionThatMightFail, { usePrometheus: true }); | ||
// In an express app, expose the metrics to the Prometheus server | ||
app.use('/metrics', (req, res) => { | ||
res.type('text/plain'); | ||
res.send(opossum.metrics()); | ||
}); | ||
``` | ||
The `prometheusRegistry` option allows to provide a existing | ||
[prom-client](https://github.com/siimon/prom-client) registry. | ||
The metrics about the circuit will be added to the provided registry instead | ||
of the global registry. | ||
The [default metrics](https://github.com/siimon/prom-client#default-metrics) | ||
will not be added to the provided registry. | ||
```js | ||
const opossum = require('opossum'); | ||
const { Registry } = require('prom-client'); | ||
// Create a registry | ||
const prometheusRegistry = new Registry(); | ||
// create a circuit | ||
const circuit = opossum(functionThatMightFail, { | ||
usePrometheus: true, | ||
prometheusRegistry | ||
}); | ||
``` | ||
#### Hystrix | ||
The [`opossum-hystrix`](https://github.com/nodeshift/opossum-hystrix) module can | ||
be used to produce metrics that are consumable by the Hystrix Dashboard. | ||
**NOTE: Hystrix metrics are deprecated** | ||
A Hystrix Stream is available for use with a Hystrix Dashboard using the `circuitBreaker.hystrixStats.getHystrixStream` method. | ||
This method returns a [Node.js Stream](https://nodejs.org/api/stream.html), which makes it easy to create an SSE stream that will be compliant with a Hystrix Dashboard. | ||
Additional Reading: [Hystrix Metrics Event Stream](https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-metrics-event-stream), [Turbine](https://github.com/Netflix/Turbine/wiki), [Hystrix Dashboard](https://github.com/Netflix/Hystrix/wiki/Dashboard) | ||
## Troubleshooting | ||
@@ -315,3 +275,3 @@ | ||
This typically occurs when you have created more than ten `CircuitBreaker` instances. This is due to the fact that every circuit created is adding a listener to the stream accessed via `circuit.stats.getHystrixStream()`, and the default `EventEmitter` listener limit is 10. In some cases, seeing this error might indicate a bug in client code, where many `CircuitBreaker`s are inadvertently being created. But there are legitimate scenarios where this may not be the case. For example, it could just be that you need more than 10 `CircuitBreaker`s in your app. That's ok. | ||
In some cases, seeing this error might indicate a bug in client code, where many `CircuitBreaker`s are inadvertently being created. But there are legitimate scenarios where this may not be the case. For example, it could just be that you need more than 10 `CircuitBreaker`s in your app. That's ok. | ||
@@ -318,0 +278,0 @@ To get around the error, you can set the number of listeners on the stream. |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
0
0
432275
13
3686
275
- Removedprom-client@^11.2.1
- Removedbintrees@1.0.2(transitive)
- Removedprom-client@11.5.3(transitive)
- Removedtdigest@0.1.2(transitive)