brakes
Version:
Node.js Circuit Breaker Pattern
137 lines (124 loc) • 4.66 kB
JavaScript
;
const Promise = require('bluebird');
const callbacks = ['cb', 'callback', 'callback_', 'done'];
function hasCallback(fn) {
const args = getFnArgs(fn);
const callbackCandidate = args[args.length - 1];
return callbacks.indexOf(callbackCandidate) > -1;
}
function promisifyIfFunction(fn, isPromise, isFunction) {
if (isPromise) {
return fn;
}
if (isFunction || hasCallback(fn)) {
return Promise.promisify(fn);
}
return fn;
}
/*
* Return a list arguments for a function
*/
function getFnArgs(fn) {
const match = fn.toString().match(/^[function\s]?.*?\(([^)]*)\)/);
let args = '';
if (!match) {
const matchSingleArg = fn.toString().match(/^([^)]*) =>/);
if (matchSingleArg) {
args = matchSingleArg[1];
}
}
else {
args = match[1];
}
// Split the arguments string into an array comma delimited.
return args.split(', ')
.map(arg => arg.replace(/\/\*.*\*\//, '').trim())
.filter(arg => arg);
}
/*
* Map a brakes stats object to a hystrix stats object
*/
function mapToHystrixJson(json) {
const stats = json.stats;
return {
type: 'HystrixCommand',
name: json.name,
group: json.group,
currentTime: json.time,
isCircuitBreakerOpen: json.open,
errorPercentage: (stats.total) ? Math.round((1 - stats.successful / stats.total) * 100) : 0,
errorCount: stats.failed,
requestCount: stats.total,
rollingCountBadRequests: 0, // not reported
rollingCountCollapsedRequests: 0, // not reported
rollingCountExceptionsThrown: 0, // not reported
rollingCountFailure: stats.failed,
rollingCountFallbackFailure: 0, // not reported
rollingCountFallbackRejection: 0, // not reported
rollingCountFallbackSuccess: 0, // not reported
rollingCountResponsesFromCache: 0, // not reported
rollingCountSemaphoreRejected: 0, // not reported
rollingCountShortCircuited: stats.shortCircuited, // not reported
rollingCountSuccess: stats.successful,
rollingCountThreadPoolRejected: 0, // not reported
rollingCountTimeout: stats.timedOut,
currentConcurrentExecutionCount: 0, // not reported
latencyExecute_mean: stats.latencyMean,
latencyExecute: {
0: stats.percentiles['0'],
25: stats.percentiles['0.25'],
50: stats.percentiles['0.5'],
75: stats.percentiles['0.75'],
90: stats.percentiles['0.9'],
95: stats.percentiles['0.95'],
99: stats.percentiles['0.99'],
99.5: stats.percentiles['0.995'],
100: stats.percentiles['1']
},
latencyTotal_mean: 15,
latencyTotal: {
0: stats.percentiles['0'],
25: stats.percentiles['0.25'],
50: stats.percentiles['0.5'],
75: stats.percentiles['0.75'],
90: stats.percentiles['0.9'],
95: stats.percentiles['0.95'],
99: stats.percentiles['0.99'],
99.5: stats.percentiles['0.995'],
100: stats.percentiles['1']
},
propertyValue_circuitBreakerRequestVolumeThreshold: json.waitThreshold,
propertyValue_circuitBreakerSleepWindowInMilliseconds: json.circuitDuration,
propertyValue_circuitBreakerErrorThresholdPercentage: json.threshold,
propertyValue_circuitBreakerForceOpen: false, // not reported
propertyValue_circuitBreakerForceClosed: false, // not reported
propertyValue_circuitBreakerEnabled: true, // not reported
propertyValue_executionIsolationStrategy: 'THREAD', // not reported
propertyValue_executionIsolationThreadTimeoutInMilliseconds: 800, // not reported
propertyValue_executionIsolationThreadInterruptOnTimeout: true, // not reported
propertyValue_executionIsolationThreadPoolKeyOverride: null, // not reported
propertyValue_executionIsolationSemaphoreMaxConcurrentRequests: 20, // not reported
propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests: 10, // not reported
propertyValue_metricsRollingStatisticalWindowInMilliseconds: 10000, // not reported
propertyValue_requestCacheEnabled: false, // not reported
propertyValue_requestLogEnabled: false, // not reported
reportingHosts: 1, // not reported
countTotal: stats.countTotal,
countSuccess: stats.countSuccess,
countFailure: stats.countFailure,
countTimeout: stats.countTimeout,
countShortCircuited: stats.countShortCircuited,
countTotalDeriv: stats.countTotalDeriv,
countSuccessDeriv: stats.countSuccessDeriv,
countFailureDeriv: stats.countFailureDeriv,
countTimeoutDeriv: stats.countTimeoutDeriv,
countShortCircuitedDeriv: stats.countShortCircuitedDeriv,
};
}
module.exports = {
callbacks,
hasCallback,
promisifyIfFunction,
getFnArgs,
mapToHystrixJson
};