Security News
tea.xyz Spam Plagues npm and RubyGems Package Registries
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
hystrixjs
Advanced tools
Readme
This library is inspired by the by the the Netflix Hystrix module for Java applications, which "is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable".
Install the hystrixjs via npm.
npm --save hystrixjs
RxJs is required for the optional monitoring event stream.
RxJs 5 is an peer dependency and will
generate an NPM warning if missing. RxJs 3 and 4
are supported as peers but are deprecated and not listed in the package.json
of this project. If you have included rx@>=3.0.0
or are not using the
monitoring event stream you can ignore NPM's peer dependency warning.
For more details see Monitoring below.
Basically it tries to achieve the same goals as the original Netflix implementation:
Since this library targets nodejs application, it is by far not as complex as the java implementation (remember... just one thread... no concurrency, at least most of the time...). So how does it accomplish the goals outlined above:
Following diagram shows what happens when a function call is wrapped in a Command
The Command is constructed with the help of the CommandsFactory. It expects a unique key and a "run" function, which will be called, when the command is executed. Note: the function must return a Promise. The returned object provides an execute() method, which will call the specified "run" function with the passed arguments. Within the execute() method it will check if the overall request volume threshold has been reached. If the command is already executing a certain amount of requests, the request will be rejected immediately to avoid overloading the downstream service and the fallback will be returned instead. If the threshold is not reached it will check if the circuit breaker is open (or "tripped") and if it is, it will forward the execution to the fallback function with the Error("OpenCircuitError"). If the circuit is closed, the command will call the provided "run" function. If the function times out or fails, the execution will be forwarded to the fallback method with the Error("CommandTimeOut") or the execution error respectively. Per default the fallback function rejects the promise with the passed error. It could however implement a logic to provide a generic response, which does not depend on network calls. If the "run" function succeeds, the command will return a Promise resolving with the response, after it performs some metrics logging.
The circuit breaker follows the same logic as the one in the original Hystrix Module. In short following steps are performed to calculate the health:
All external communication points should be wrapped within a command. The command factory is the entry point to get the existing or generate a new command.
var CommandsFactory = require('hystrixjs').commandFactory;
var serviceCommand = CommandsFactory.getOrCreate("Service on port :" + service.port + ":" + port)
.circuitBreakerErrorThresholdPercentage(service.errorThreshold)
.timeout(service.timeout)
.run(makeRequest)
.circuitBreakerRequestVolumeThreshold(service.concurrency)
.circuitBreakerSleepWindowInMilliseconds(service.timeout)
.statisticalWindowLength(10000)
.statisticalWindowNumberOfBuckets(10)
.errorHandler(isErrorHandler)
.build();
Each generated command is cached based on its key supplied as the first parameter. The "getOrCreate()" method returns a "CommandBuilder" object, which provides methods for configuration of:
All of these options have defaults and does not have to be configured. See HystrixConfig for details. These can be overridden on app startup.
To execute a command just call the "execute" method and pass the parameters:
var promise = serviceCommand.execute(arguments)
The arguments will be passed into the run function and the result will be a promise. If the run function fails, the arguments will passed to the fallback function (in an array) as the 2nd argument.
Testing could be tricky, especially because the library introduces state, which could interfere between the single unit tests. In order to avoid this kind of problems the library provides access to the factories producing metrics, circuits and commands. These can be used to reset the state before each test:
var commandFactory = require('hystrixjs').commandFactory;
var metricsFactory = require('hystrixjs').metricsFactory;
var circuitFactory = require('hystrixjs').circuitFactory;
metricsFactory.resetCache();
circuitFactory.resetCache();
commandFactory.resetCache();
The same problems occur during integration tests, only in this case there is no direct access to the artifacts. There could be two different strategies to solve this problem:
Another question is, how to actually test, that the library is used correctly. Specifically, it should be possible to test, that if the circuit is open, the service under test is not calling the 3rd party services and the command returns a correct error message (e.g. 503 Service is unavailable). Now the biggest problem is to generate a load on the service to make the command to actually trip the circuit. Remember circuitBreakerRequestVolumeThreshold, the circuit breaker won't do anything, if the load on the 3rd party library is not high enough. To tackle this kind of problem one could:
HystrixConfig provides two configuration options with the following defaults:
"hystrix.circuit.volumeThreshold.forceOverride": false,
"hystrix.circuit.volumeThreshold.override": 10,
Depending on the environment the service is being started in, these options can be overridden:
var hystrixConfig = require('hystrixjs').hystrixConfig;
if (localEnv) {
hystrixConfig.init({
"hystrix.circuit.volumeThreshold.forceOverride": true,
"hystrix.circuit.volumeThreshold.override": 0
});
}
This will make the library to always check the circuit breaker before executing a request. So now the circuit can be tripped by a deliberately false request, which would record a failure and bump the error percentage to 100%. The subsequent request, which should normally return a 200 response, should fail with 503 response:
makeRequest('returning-http-500').fail(function (json) {
expect(json).toEqual({
errors: [{
message: 'There was an unexpected error.'
}]
});
makeRequest('returning-success-200').fail(function (json) {
expect(json).toEqual({
errors: [{
message: 'Service unavailable.'
}]
});
}).then(failTest(done));
}).then(failTest(done));
The library provides a module HystrixSSEStream to export gathered metrics as a server side events stream. This stream can be used with Hystrix Dashboard to visualise the current state of the service, or its external communication points to be more precise:
In order to use this the service must include RxJs, either from
rx@>=3.0.0
or
rxjs@^5.0.0
, and
expose a monitoring end point, which writes the SSE data into response:
var hystrixSSEStream = require('hystrixjs').hystrixSSEStream;
function hystrixStreamResponse(request, response) {
response.append('Content-Type', 'text/event-stream;charset=UTF-8');
response.append('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate');
response.append('Pragma', 'no-cache');
return hystrixSSEStream.toObservable().subscribe(
function onNext(sseData) {
response.write('data: ' + sseData + '\n\n');
},
function onError(error) {
console.log(error);
},
function onComplete() {
return response.end();
}
);
};
Failure to include either rx
or rxjs
will throw an Error at load
time. If both rx
and rxjs
are included, rxjs
will be used.
HystrixJS can work with any ES6 compatible promise implementation. By default all promises returned will be built-in Node.js promises. To configure another library, specify the promise implementation when initializing the HystrixConfig
module. E.g. for Bluebird:
var Promise = require('bluebird');
// Or Q
// var Promise = require('q').Promise;
var hystrixConfig = require('hystrixjs').hystrixConfig;
hystrixConfig.init({
// any other hystrix options...
"hystrix.promise.implementation": Promise
});
FAQs
resilience module for NodeJS applications
The npm package hystrixjs receives a total of 1,455 weekly downloads. As such, hystrixjs popularity was classified as popular.
We found that hystrixjs demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
Security News
As cyber threats become more autonomous, AI-powered defenses are crucial for businesses to stay ahead of attackers who can exploit software vulnerabilities at scale.
Security News
UnitedHealth Group disclosed that the ransomware attack on Change Healthcare compromised protected health information for millions in the U.S., with estimated costs to the company expected to reach $1 billion.