From 9f27624c0ca2fb53ddcf8e633d02b6f105bac046 Mon Sep 17 00:00:00 2001 From: Pranav Ravichandran Date: Mon, 18 Sep 2017 17:56:51 -0700 Subject: [PATCH] Add errorFn option to breaker to filter errors --- lib/circuit-breaker.js | 5 +++- package.json | 2 +- test/circuitbreaker-test.js | 49 +++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/lib/circuit-breaker.js b/lib/circuit-breaker.js index f6e4bc6..bd8b016 100644 --- a/lib/circuit-breaker.js +++ b/lib/circuit-breaker.js @@ -18,6 +18,7 @@ var CircuitBreaker = module.exports = function (func, options) { this.timeout = this.options.timeout || 10000; // default 10 second timeout (ms) this.resetTimeout = this.options.resetTimeout || 60000; // default 1 minute reset timeout (ms) this.maxFailures = this.options.maxFailures || 5; // default max number of failures to open circuit + this.errorFn = this.options.errorFn || function () { return true; }; // optional function to break based on custom conditions for error object // Initially circuit is always closed this.forceClosed(); @@ -90,7 +91,9 @@ CircuitBreaker.prototype._callbackHandler = function(deferred, timeoutID, startT self.emit('latency', (new Date() - startTime) ); if(err) { - self.handleFailure(err); + if(self.errorFn(err)) { + self.handleFailure(err); + } deferred.reject(err); } else { self.handleSuccess(); diff --git a/package.json b/package.json index ca15d6b..978e8dc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "circuitbreaker", - "version": "0.2.1", + "version": "0.3.0", "description": "circuit breaker is used to provide stability and prevent cascading failures in distributed systems", "main": "index.js", "scripts": { diff --git a/test/circuitbreaker-test.js b/test/circuitbreaker-test.js index 8704532..453a8b2 100644 --- a/test/circuitbreaker-test.js +++ b/test/circuitbreaker-test.js @@ -371,4 +371,53 @@ describe('Circuit Breaker', function(){ }); }); + + describe('errorFn', function () { + it('should break based on error function parameter', function (done) { + var breakerFn = function(id, callback) { + if (id < 0) { + return callback(id); + } else { + return callback(null, 'data for id ' + id); + } + }; + + var breaker = new CircuitBreaker(breakerFn, {timeout: 10, maxFailures: 3, resetTimeout: 30, errorFn: function (error) { if (error === -2) { return false; } return true }}); + var noop = function () {}; + + breaker.invoke(-1).fail(noop); + breaker.invoke(-2).fail(noop); + breaker.invoke(-1).fail(noop); + breaker.isClosed().should.be.true; + + breaker.invoke(-1).fail(noop); + breaker.isOpen().should.be.true; + + done(); + }); + + it('should break the circuit normally without an error function', function (done) { + var breakerFn = function(id, callback) { + if (id < 0) { + return callback(id); + } else { + return callback(null, 'data for id ' + id); + } + }; + + var breaker = new CircuitBreaker(breakerFn, {timeout: 10, maxFailures: 3, resetTimeout: 30}); + var noop = function () {}; + + breaker.invoke(-1).fail(noop); + breaker.invoke(-2).fail(noop); + breaker.invoke(-1).fail(noop); + breaker.isClosed().should.be.false; + + breaker.invoke(-1).fail(noop); + breaker.isOpen().should.be.true; + + done(); + }); + + }); });