Skip to content

Commit

Permalink
feat: Add caching capability to circuits
Browse files Browse the repository at this point in the history
  • Loading branch information
helio-frota committed Mar 7, 2017
1 parent 6c14b39 commit 0b717f6
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 1 deletion.
23 changes: 22 additions & 1 deletion lib/circuit.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const PENDING_CLOSE = Symbol('pending-close');
const FALLBACK_FUNCTION = Symbol('fallback');
const NUM_FAILURES = Symbol('num-failures');
const STATUS = Symbol('status');
const CACHE = new WeakMap();

/**
* @class CircuitBreaker
Expand Down Expand Up @@ -62,6 +63,9 @@ class CircuitBreaker extends EventEmitter {

this.on('open', _startTimer(this));
this.on('success', () => this.close());
if (this.options.cache) {
CACHE.set(this, undefined);
}
}

/**
Expand Down Expand Up @@ -165,6 +169,12 @@ class CircuitBreaker extends EventEmitter {
* @fires CircuitBreaker#timeout
*/
fire () {
if (CACHE.get(this) !== undefined) {
this.emit('cacheHit');
return CACHE.get(this);
} else {
this.emit('cacheMiss');
}
const args = Array.prototype.slice.call(arguments);
/**
* Emitted when the circuit breaker action is executed
Expand All @@ -185,7 +195,7 @@ class CircuitBreaker extends EventEmitter {

let timeout;
let timeoutError = false;
return new this.Promise((resolve, reject) => {
const value = new this.Promise((resolve, reject) => {
timeout = setTimeout(
() => {
timeoutError = true;
Expand Down Expand Up @@ -222,6 +232,17 @@ class CircuitBreaker extends EventEmitter {
handleError(error, this, timeout, args, resolve, reject);
}
});
if (this.options.cache) {
CACHE.set(this, value);
}
return value;
}

/**
* Clears the cache of this {@link CircuitBreaker}
*/
clearCache () {
CACHE.set(this, undefined);
}
}

Expand Down
10 changes: 10 additions & 0 deletions lib/status.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,23 @@ class Status {
* The number of times this circuit breaker has timed out
*/
this.timeouts = 0;
/**
* The number of times the cache is used
*/
this.cacheHit = 0;
/**
* The number of times the cache is missed
*/
this.cacheMiss = 0;
this[CIRCUIT_BREAKER] = circuit;
circuit.on('success', () => this.successes++);
circuit.on('failure', () => this.failures++);
circuit.on('fallback', () => this.fallbacks++);
circuit.on('timeout', () => this.timeouts++);
circuit.on('fire', () => this.fires++);
circuit.on('reject', () => this.rejects++);
circuit.on('cacheHit', () => this.cacheHit++);
circuit.on('cacheMiss', () => this.cacheMiss++);
}
}

Expand Down
29 changes: 29 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,35 @@ test('Passes parameters to the circuit function', (t) => {
.catch(t.fail);
});

test('Using cache', (t) => {
t.plan(3);
const expected = 34;
const options = {
cache: true
};
const breaker = cb(passFail, options);

breaker.fire(expected)
.then((arg) => t.equals(arg, expected, `cache hits:misses ${breaker.status.cacheHit}:${breaker.status.cacheMiss}`))
.catch(t.fail)
.then(() => {
breaker.fire(expected)
.then((arg) => {
t.equals(arg, expected, `cache hits:misses ${breaker.status.cacheHit}:${breaker.status.cacheMiss}`);
breaker.clearCache();
})
.catch(t.fail)
.then(() => {
breaker.fire(expected)
.then((arg) => {
t.equals(arg, expected, `cache hits:misses ${breaker.status.cacheHit}:${breaker.status.cacheMiss}`);
})
.then(t.end)
.catch(t.fail);
});
});
});

test('Fails when the circuit function fails', (t) => {
t.plan(1);
const breaker = cb(passFail);
Expand Down

0 comments on commit 0b717f6

Please sign in to comment.