Comparing version 0.5.1 to 0.6.0
@@ -5,2 +5,25 @@ # Change Log | ||
<a name="0.6.0"></a> | ||
# [0.6.0](https://github.com/bucharest-gold/opossum/compare/v0.5.1...v0.6.0) (2017-03-30) | ||
### Bug Fixes | ||
* circuit should emit failure event on fallback ([f2594d8](https://github.com/bucharest-gold/opossum/commit/f2594d8)) | ||
* include the error when emitting the 'fallback event' ([40eb2eb](https://github.com/bucharest-gold/opossum/commit/40eb2eb)) | ||
* promise should reject when action throws ([58dab98](https://github.com/bucharest-gold/opossum/commit/58dab98)) | ||
* typo copy past duplicated property ([54a27b9](https://github.com/bucharest-gold/opossum/commit/54a27b9)) | ||
### Features | ||
* add basic rolling stats to a circuit ([8fb9561](https://github.com/bucharest-gold/opossum/commit/8fb9561)) | ||
* Add caching capability to circuits ([6c3144f](https://github.com/bucharest-gold/opossum/commit/6c3144f)) | ||
* Add caching capability to circuits ([0b717f6](https://github.com/bucharest-gold/opossum/commit/0b717f6)) | ||
* Applying code review ([6a0f7ff](https://github.com/bucharest-gold/opossum/commit/6a0f7ff)) | ||
* Applying code review ([8445a24](https://github.com/bucharest-gold/opossum/commit/8445a24)) | ||
* circuits now have a name based on the action ([f08d46e](https://github.com/bucharest-gold/opossum/commit/f08d46e)) | ||
<a name="0.5.1"></a> | ||
@@ -7,0 +30,0 @@ ## [0.5.1](https://github.com/bucharest-gold/opossum/compare/v0.5.0...v0.5.1) (2017-03-02) |
@@ -1,2 +0,2 @@ | ||
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f;}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e);},l,l.exports,e,t,n,r);}return n[o].exports;}for(var i=typeof require=="function"&&require,o=0;o<r.length;o++)s(r[o]);return s;})({1:[function(c,d,h){(function(j){(()=>{'use strict';const k=c('./lib/circuit'),q=c('fidelity'),w={timeout:10000,maxFailures:10,resetTimeout:30000,Promise:q};function circuitBreaker(z,A){return new k(z,Object.assign({},w,A));}circuitBreaker.promisify=c('./lib/promisify');if(typeof window==='object'){window[circuitBreaker.name]=circuitBreaker;}if(typeof j==='object'){d.exports=h=circuitBreaker;}}).call();}).call(this,c('_process'));},{"./lib/circuit":2,"./lib/promisify":3,"_process":7,"fidelity":6}],2:[function(B,C,D){'use strict';const E=B('events'),F=B('./status'),G=Symbol('state'),H=Symbol('open'),I=Symbol('closed'),J=Symbol('half-open'),K=Symbol('pending-close'),L=Symbol('fallback'),M=Symbol('num-failures'),N=Symbol('status');class CircuitBreaker extends E{constructor(O,P){super();this.options=P;this.Promise=P.Promise;this[N]=new F(this);this[G]=I;this[L]=null;this[K]=!1;this[M]=0;if(typeof O!=='function')this.action=()=>this.Promise.resolve(O);else this.action=O;function _startTimer(Q){return()=>{const R=setTimeout(()=>{Q[G]=J;Q.emit('halfOpen',Q.options.resetTimeout);},Q.options.resetTimeout);if(typeof R.unref==='function'){R.unref();}};}this.on('open',_startTimer(this));this.on('success',()=>this.close());}close(){this[M]=0;this[K]=!1;if(this[G]!==I){this[G]=I;this.emit('close');}}open(){this[K]=!1;if(this[G]!==H){this[G]=H;this.emit('open');}}get closed(){return this[G]===I;}get opened(){return this[G]===H;}get halfOpen(){return this[G]===J;}get status(){return this[N];}fallback(S){let T=S;if(S instanceof CircuitBreaker){T=function(){return S.fire.apply(S,arguments);};}this[L]=T;return this;}fire(){const U=Array.prototype.slice.call(arguments);this.emit('fire',U);if(this.opened||this.halfOpen&&this[K]){this.emit('reject',new Error('Breaker is open'));return fallback(this,U)||fail(this,'Breaker is open',U);}this[K]=this.halfOpen;let V,W=!1;try{return new this.Promise((X,Y)=>{V=setTimeout(()=>{W=!0;const Z=new Error(`Timed out after ${this.options.timeout}ms`);this.emit('timeout',Z);X(fallback(this,U)||fail(this,Z,U));},this.options.timeout);const a1=this.action.apply(this.action,U),b1=typeof a1.then==='function'?a1:this.Promise.resolve(a1);b1.then(c1=>{if(!W){this.emit('success',c1);X(c1);clearTimeout(V);}}).catch(d1=>{clearTimeout(V);const fb=fallback(this,U);if(fb)return X(fb);fail(this,d1,U);Y(d1);});});}catch(error){clearTimeout(V);return fallback(this,U)||fail(this,error,U);}}}function fallback(f1,g1){if(f1[L]){return new f1.Promise((h1,i1)=>{const j1=f1[L].apply(f1[L],g1);f1.emit('fallback',j1);h1(j1);});}}function fail(k1,l1,m1){k1.emit('failure',l1);k1[M]+=1;if(k1[M]>=k1.options.maxFailures){k1.open();}return k1.Promise.reject.apply(null,[l1]);}C.exports=D=CircuitBreaker;},{"./status":4,"events":5}],3:[function(n1,o1,p1){'use strict';const q1=n1('fidelity');o1.exports=p1=function promisify(r1){return function promisifiedFunction(){return new q1((s1,t1)=>{const cb=(u1,v1)=>{if(u1)t1(u1);s1(v1);},w1=Array.prototype.slice.call(arguments);w1.push(cb);r1.apply(r1,w1);});};};},{"fidelity":6}],4:[function(x1,y1,z1){'use strict';const A1=Symbol('circuit-breaker');class Status{constructor(B1){this.failures=0;this.fallbacks=0;this.successes=0;this.rejects=0;this.fires=0;this.timeouts=0;this[A1]=B1;B1.on('success',()=>this.successes++);B1.on('failure',()=>this.failures++);B1.on('fallback',()=>this.fallbacks++);B1.on('timeout',()=>this.timeouts++);B1.on('fire',()=>this.fires++);B1.on('reject',()=>this.rejects++);}}y1.exports=z1=Status;},{}],5:[function(C1,D1,E1){function EventEmitter(){this._events=this._events||{};this._maxListeners=this._maxListeners||void 0;}D1.exports=EventEmitter;EventEmitter.EventEmitter=EventEmitter;EventEmitter.prototype._events=void 0;EventEmitter.prototype._maxListeners=void 0;EventEmitter.defaultMaxListeners=10;EventEmitter.prototype.setMaxListeners=function(n){if(!isNumber(n)||n<0||isNaN(n))throw TypeError('n must be a positive number');this._maxListeners=n;return this;};EventEmitter.prototype.emit=function(F1){var er,H1,I1,J1,i,K1;if(!this._events)this._events={};if(F1==='error'){if(!this._events.error||isObject(this._events.error)&&!this._events.error.length){er=arguments[1];if(er instanceof Error){throw er;}else{var L1=new Error('Uncaught, unspecified "error" event. ('+er+')');L1.context=er;throw L1;}}}H1=this._events[F1];if(isUndefined(H1))return!1;if(isFunction(H1)){switch(arguments.length){case 1:H1.call(this);break;case 2:H1.call(this,arguments[1]);break;case 3:H1.call(this,arguments[1],arguments[2]);break;default:J1=Array.prototype.slice.call(arguments,1);H1.apply(this,J1);}}else if(isObject(H1)){J1=Array.prototype.slice.call(arguments,1);K1=H1.slice();I1=K1.length;for(i=0;i<I1;i++)K1[i].apply(this,J1);}return!0;};EventEmitter.prototype.addListener=function(M1,N1){var m;if(!isFunction(N1))throw TypeError('listener must be a function');if(!this._events)this._events={};if(this._events.newListener)this.emit('newListener',M1,isFunction(N1.listener)?N1.listener:N1);if(!this._events[M1])this._events[M1]=N1;else if(isObject(this._events[M1]))this._events[M1].push(N1);else this._events[M1]=[this._events[M1],N1];if(isObject(this._events[M1])&&!this._events[M1].warned){if(!isUndefined(this._maxListeners)){m=this._maxListeners;}else{m=EventEmitter.defaultMaxListeners;}if(m&&m>0&&this._events[M1].length>m){this._events[M1].warned=!0;console.error('(node) warning: possible EventEmitter memory '+'leak detected. %d listeners added. '+'Use emitter.setMaxListeners() to increase limit.',this._events[M1].length);if(typeof console.trace==='function'){console.trace();}}}return this;};EventEmitter.prototype.on=EventEmitter.prototype.addListener;EventEmitter.prototype.once=function(O1,P1){if(!isFunction(P1))throw TypeError('listener must be a function');var Q1=!1;function g(){this.removeListener(O1,g);if(!Q1){Q1=!0;P1.apply(this,arguments);}}g.listener=P1;this.on(O1,g);return this;};EventEmitter.prototype.removeListener=function(R1,S1){var T1,U1,V1,i;if(!isFunction(S1))throw TypeError('listener must be a function');if(!this._events||!this._events[R1])return this;T1=this._events[R1];V1=T1.length;U1=-1;if(T1===S1||isFunction(T1.listener)&&T1.listener===S1){delete this._events[R1];if(this._events.removeListener)this.emit('removeListener',R1,S1);}else if(isObject(T1)){for(i=V1;i-->0;){if(T1[i]===S1||T1[i].listener&&T1[i].listener===S1){U1=i;break;}}if(U1<0)return this;if(T1.length===1){T1.length=0;delete this._events[R1];}else{T1.splice(U1,1);}if(this._events.removeListener)this.emit('removeListener',R1,S1);}return this;};EventEmitter.prototype.removeAllListeners=function(W1){var X1,Y1;if(!this._events)return this;if(!this._events.removeListener){if(arguments.length===0)this._events={};else if(this._events[W1])delete this._events[W1];return this;}if(arguments.length===0){for(X1 in this._events){if(X1==='removeListener')continue;this.removeAllListeners(X1);}this.removeAllListeners('removeListener');this._events={};return this;}Y1=this._events[W1];if(isFunction(Y1)){this.removeListener(W1,Y1);}else if(Y1){while(Y1.length)this.removeListener(W1,Y1[Y1.length-1]);}delete this._events[W1];return this;};EventEmitter.prototype.listeners=function(Z1){var a2;if(!this._events||!this._events[Z1])a2=[];else if(isFunction(this._events[Z1]))a2=[this._events[Z1]];else a2=this._events[Z1].slice();return a2;};EventEmitter.prototype.listenerCount=function(b2){if(this._events){var c2=this._events[b2];if(isFunction(c2))return 1;else if(c2)return c2.length;}return 0;};EventEmitter.listenerCount=function(d2,e2){return d2.listenerCount(e2);};function isFunction(f2){return typeof f2==='function';}function isNumber(g2){return typeof g2==='number';}function isObject(h2){return typeof h2==='object'&&h2!==null;}function isUndefined(i2){return i2===void 0;}},{}],6:[function(j2,k2,l2){(function(m2){(function(){'use strict';var n2=typeof m2==='object'&&m2&&m2.Object===Object&&m2,o2=n2||Function('return this')();const p2=0,q2=1,r2=2,s2=Symbol('handlers'),t2=Symbol('queue'),u2=Symbol('state'),v2=Symbol('value');class FidelityPromise{constructor(fn){this[t2]=[];this[s2]=new Handlers();this[u2]=p2;this[v2]=void 0;const x2=typeof fn;if(x2==='function'){tryFunction(fn,this);}else if(x2!=='undefined'){resolvePromise(this,fn);}}get state(){return this[u2];}get value(){return this[v2];}then(y2,z2){const A2=new FidelityPromise();if(typeof y2==='function'){A2[s2].fulfill=y2;}if(typeof z2==='function'){A2[s2].reject=z2;}this[t2].push(A2);process(this);return A2;}catch(B2){return this.then(null,B2);}static promise(fn){console.error('Fidelity.promise() is deprecated. Use `new Fidelity.Promise()`.');return new FidelityPromise(fn);}static deferred(){let D2,E2;const p=new FidelityPromise((F2,G2)=>{D2=F2;E2=G2;});return{promise:p,resolve:H2=>D2(H2),reject:I2=>E2(I2)};}static resolve(J2){if(J2&&J2.then)return J2;switch(J2){case null:return W2;case!0:return U2;case!1:return V2;case 0:return X2;case'':return Y2;}const p=new FidelityPromise();p[u2]=q2;p[v2]=J2;return p;}static reject(K2){const p=new FidelityPromise();p[u2]=r2;p[v2]=K2;return p;}static all(){const L2=[],M2=Array.from(arguments).reduce((a,b)=>a.concat(b),[]),N2=M2.reduce((O2,p)=>O2.then(()=>p).then(r=>L2.push(r)),Promise.resolve(null));return N2.then(_=>L2);}static race(){const P2=Array.from(arguments).reduce((a,b)=>a.concat(b),[]);return new FidelityPromise((Q2,R2)=>{P2.forEach(p=>p.then(Q2).catch(R2));});}}FidelityPromise.PENDING=p2;FidelityPromise.FULFILLED=q2;FidelityPromise.REJECTED=r2;class Handlers{constructor(){this.fulfill=null;this.reject=null;}}const S2=(()=>{if(o2.process&&typeof o2.process.nextTick==='function'){return o2.process.nextTick;}else if(typeof o2.setImmediate==='function'){return o2.setImmediate;}else if(typeof o2.setTimeout==='function'){return(f,p)=>o2.setTimeout(f,0,p);}else{console.error('No nextTick. How we gonna do this?');return(f,p)=>f.call(this,p);}})();function exportModule(T2){if(typeof k2==='object'&&k2.exports){k2.exports=T2;}else{o2[T2.name]=T2;}}const U2=new FidelityPromise(!0),V2=new FidelityPromise(!1),W2=new FidelityPromise(null),X2=new FidelityPromise(0),Y2=new FidelityPromise('');function tryFunction(fn,a3){try{fn(v=>resolvePromise(a3,v),r=>transition(a3,r2,r));}catch(e){transition(a3,r2,e);}}function resolvePromise(p,x){if(x===p){transition(p,r2,new TypeError('The promise and its value are the same.'));return;}const b3=typeof x;if(x&&(b3==='function'||b3==='object')){let c3=!1;try{const d3=x.then;if(d3&&typeof d3==='function'){d3.call(x,y=>{if(!c3){resolvePromise(p,y);c3=!0;}},r=>{if(!c3){transition(p,r2,r);c3=!0;}});}else{transition(p,q2,x);c3=!0;}}catch(e){if(!c3){transition(p,r2,e);c3=!0;}}}else{transition(p,q2,x);}}function process(p){if(p[u2]===p2)return;S2(processNextTick,p);return p;}function processNextTick(p){let e3,qp;while(p[t2].length){qp=p[t2].shift();if(p[u2]===q2){e3=qp[s2].fulfill||(v=>v);}else if(p[u2]===r2){e3=qp[s2].reject||(r=>{throw r;});}try{resolvePromise(qp,e3(p[v2]));}catch(e){transition(qp,r2,e);continue;}}}function transition(p,g3,h3){if(p[u2]===g3||p[u2]!==p2)return;p[u2]=g3;p[v2]=h3;return process(p);}exportModule(FidelityPromise);}).call(this);}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});},{}],7:[function(i3,j3,k3){var l3=j3.exports={},m3,n3;function defaultSetTimout(){throw new Error('setTimeout has not been defined');}function defaultClearTimeout(){throw new Error('clearTimeout has not been defined');}(function(){try{if(typeof setTimeout==='function'){m3=setTimeout;}else{m3=defaultSetTimout;}}catch(e){m3=defaultSetTimout;}try{if(typeof clearTimeout==='function'){n3=clearTimeout;}else{n3=defaultClearTimeout;}}catch(e){n3=defaultClearTimeout;}})();function runTimeout(o3){if(m3===setTimeout){return setTimeout(o3,0);}if((m3===defaultSetTimout||!m3)&&setTimeout){m3=setTimeout;return setTimeout(o3,0);}try{return m3(o3,0);}catch(e){try{return m3.call(null,o3,0);}catch(e){return m3.call(this,o3,0);}}}function runClearTimeout(p3){if(n3===clearTimeout){return clearTimeout(p3);}if((n3===defaultClearTimeout||!n3)&&clearTimeout){n3=clearTimeout;return clearTimeout(p3);}try{return n3(p3);}catch(e){try{return n3.call(null,p3);}catch(e){return n3.call(this,p3);}}}var q3=[],r3=!1,s3,t3=-1;function cleanUpNextTick(){if(!r3||!s3){return;}r3=!1;if(s3.length){q3=s3.concat(q3);}else{t3=-1;}if(q3.length){drainQueue();}}function drainQueue(){if(r3){return;}var u3=runTimeout(cleanUpNextTick);r3=!0;var v3=q3.length;while(v3){s3=q3;q3=[];while(++t3<v3){if(s3){s3[t3].run();}}t3=-1;v3=q3.length;}s3=null;r3=!1;runClearTimeout(u3);}l3.nextTick=function(w3){var x3=new Array(arguments.length-1);if(arguments.length>1){for(var i=1;i<arguments.length;i++){x3[i-1]=arguments[i];}}q3.push(new Item(w3,x3));if(q3.length===1&&!r3){runTimeout(drainQueue);}};function Item(y3,z3){this.fun=y3;this.array=z3;}Item.prototype.run=function(){this.fun.apply(null,this.array);};l3.title='browser';l3.browser=!0;l3.env={};l3.argv=[];l3.version='';l3.versions={};function noop(){}l3.on=noop;l3.addListener=noop;l3.once=noop;l3.off=noop;l3.removeListener=noop;l3.removeAllListeners=noop;l3.emit=noop;l3.binding=function(A3){throw new Error('process.binding is not supported');};l3.cwd=function(){return'/';};l3.chdir=function(B3){throw new Error('process.chdir is not supported');};l3.umask=function(){return 0;};},{}]},{},[1,2,3,4]); | ||
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f;}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e);},l,l.exports,e,t,n,r);}return n[o].exports;}for(var i=typeof require=="function"&&require,o=0;o<r.length;o++)s(r[o]);return s;})({1:[function(d,h,j){(function(k){(()=>{'use strict';const q=d('./lib/circuit'),w=d('fidelity'),z={timeout:10000,maxFailures:10,resetTimeout:30000,Promise:w};function circuitBreaker(A,B){return new q(A,Object.assign({},z,B));}circuitBreaker.promisify=d('./lib/promisify');if(typeof window==='object'){window[circuitBreaker.name]=circuitBreaker;}if(typeof k==='object'){h.exports=j=circuitBreaker;}}).call();}).call(this,d('_process'));},{"./lib/circuit":2,"./lib/promisify":4,"_process":8,"fidelity":7}],2:[function(C,D,E){'use strict';const F=C('events'),G=C('./status'),H=Symbol('state'),I=Symbol('open'),J=Symbol('closed'),K=Symbol('half-open'),L=Symbol('pending-close'),M=Symbol('fallback'),N=Symbol('num-failures'),O=Symbol('status'),P=Symbol('name'),Q=new WeakMap();class CircuitBreaker extends F{constructor(R,S){super();this.options=S;this.options.rollingCountTimeout=S.rollingCountTimeout||10000;this.Promise=S.Promise;this[O]=new G(this);this[H]=J;this[M]=null;this[L]=!1;this[N]=0;this[P]=S.name||R.name||nextName();if(typeof R!=='function')this.action=()=>this.Promise.resolve(R);else this.action=R;function _startTimer(T){return()=>{const U=setTimeout(()=>{T[H]=K;T.emit('halfOpen',T.options.resetTimeout);},T.options.resetTimeout);if(typeof U.unref==='function'){U.unref();}};}this.on('open',_startTimer(this));this.on('success',()=>this.close());if(this.options.cache){Q.set(this,void 0);}}close(){this[N]=0;this[L]=!1;if(this[H]!==J){this[H]=J;this.emit('close');}}open(){this[L]=!1;if(this[H]!==I){this[H]=I;this.emit('open');}}get name(){return this[P];}get closed(){return this[H]===J;}get opened(){return this[H]===I;}get halfOpen(){return this[H]===K;}get status(){return this[O];}fallback(V){let W=V;if(V instanceof CircuitBreaker){W=function(){return V.fire.apply(V,arguments);};}this[M]=W;return this;}fire(){if(Q.get(this)!==void 0){this.emit('cacheHits');return Q.get(this);}else if(this.options.cache){this.emit('cacheMisses');}const X=Array.prototype.slice.call(arguments);this.emit('fire',X);if(this.opened||this.halfOpen&&this[L]){this.emit('reject',new Error('Breaker is open'));const Y=fail(this,'Breaker is open',X);return fallback(this,'Breaker is open',X)||Y;}this[L]=this.halfOpen;let Z,a1=!1;return new this.Promise((b1,c1)=>{Z=setTimeout(()=>{a1=!0;const d1=new Error(`Timed out after ${this.options.timeout}ms`);this.emit('timeout',d1);b1(fallback(this,d1,X)||fail(this,d1,X));},this.options.timeout);try{const e1=this.action.apply(this.action,X),f1=typeof e1.then==='function'?e1:this.Promise.resolve(e1);f1.then(g1=>{if(!a1){this.emit('success',g1);b1(g1);if(this.options.cache){Q.set(this,f1);}clearTimeout(Z);}}).catch(h1=>handleError(h1,this,Z,X,b1,c1));}catch(error){handleError(error,this,Z,X,b1,c1);}});}clearCache(){Q.set(this,void 0);}}function handleError(i1,j1,k1,l1,m1,n1){clearTimeout(k1);fail(j1,i1,l1);const fb=fallback(j1,i1,l1);if(fb)m1(fb);else n1(i1);}function fallback(p1,q1,r1){if(p1[M]){return new p1.Promise((s1,t1)=>{const u1=p1[M].apply(p1[M],r1);p1.emit('fallback',u1,q1);s1(u1);});}}function fail(v1,w1,x1){v1.emit('failure',w1);v1[N]+=1;if(v1[N]>=v1.options.maxFailures){v1.open();}return v1.Promise.reject.apply(null,[w1]);}const nextName=()=>'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,c=>{const r=Math.random()*16|0,v=c==='x'?r:r&0x3|0x8;return v.toString(16);});D.exports=E=CircuitBreaker;},{"./status":5,"events":6}],3:[function(y1,z1,A1){'use strict';function getStreamData(B1,C1,D1){console.log(B1.status,B1.opened,B1.halfOpen,B1.closed);const E1={};E1.type='HystrixCommand';E1.name=C1;E1.group=D1;E1.currentTime=new Date();E1.isCircuitBreakerOpen=B1.opened||B1.halfOpen;E1.errorPercentage=B1.status.fires===0?0:B1.status.failures/B1.status.fires*100;E1.errorCount=B1.status.failures;E1.requestCount=B1.status.fires;E1.rollingCountBadRequests=B1.status.failures;E1.rollingCountCollapsedRequests=0;E1.rollingCountEmit=0;E1.rollingCountExceptionsThrown=0;E1.rollingCountFailure=B1.status.failures;E1.rollingCountFallbackEmit=B1.status.fallbacks;E1.rollingCountFallbackFailure=0;E1.rollingCountFallbackMissing=0;E1.rollingCountFallbackRejection=0;E1.rollingCountFallbackSuccess=0;E1.rollingCountResponsesFromCache=0;E1.rollingCountSemaphoreRejected=B1.status.rejects;E1.rollingCountShortCircuited=B1.status.rejects;E1.rollingCountSuccess=B1.status.successes;E1.rollingCountThreadPoolRejected=0;E1.rollingCountTimeout=B1.status.timeouts;E1.currentConcurrentExecutionCount=0;E1.rollingMaxConcurrentExecutionCount=0;E1.latencyExecute_mean=0;E1.latencyExecute={'0':0,'25':0,'50':0,'75':0,'90':0,'95':0,'99':0,'99.5':0,'100':0};E1.latencyTotal_mean=0;E1.latencyTotal={'0':0,'25':0,'50':0,'75':0,'90':0,'95':0,'99':0,'99.5':0,'100':0};E1.propertyValue_circuitBreakerRequestVolumeThreshold=5;E1.propertyValue_circuitBreakerSleepWindowInMilliseconds=5000;E1.propertyValue_circuitBreakerErrorThresholdPercentage=50;E1.propertyValue_circuitBreakerForceOpen=!1;E1.propertyValue_circuitBreakerForceClosed=!1;E1.propertyValue_circuitBreakerEnabled=!0;E1.propertyValue_executionIsolationStrategy='THREAD';E1.propertyValue_executionIsolationThreadTimeoutInMilliseconds=300;E1.propertyValue_executionTimeoutInMilliseconds=300;E1.propertyValue_executionIsolationThreadInterruptOnTimeout=!0;E1.propertyValue_executionIsolationThreadPoolKeyOverride=null;E1.propertyValue_executionIsolationSemaphoreMaxConcurrentRequests=10;E1.propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests=10;E1.propertyValue_metricsRollingStatisticalWindowInMilliseconds=10000;E1.propertyValue_requestCacheEnabled=!0;E1.propertyValue_requestLogEnabled=!0;E1.reportingHosts=1;return JSON.stringify(E1);}z1.exports=A1={getStreamData};},{}],4:[function(F1,G1,H1){'use strict';const I1=F1('fidelity');G1.exports=H1=function promisify(J1){return function promisifiedFunction(){return new I1((K1,L1)=>{const cb=(M1,N1)=>{if(M1)L1(M1);K1(N1);},O1=Array.prototype.slice.call(arguments);O1.push(cb);J1.apply(J1,O1);});};};},{"fidelity":7}],5:[function(P1,Q1,R1){'use strict';const S1=Symbol('circuit-breaker');class Status{constructor(T1){reset(this);this[S1]=T1;T1.on('success',()=>this.successes++);T1.on('failure',()=>this.failures++);T1.on('fallback',()=>this.fallbacks++);T1.on('timeout',()=>this.timeouts++);T1.on('fire',()=>this.fires++);T1.on('reject',()=>this.rejects++);T1.on('cacheHits',()=>this.cacheHits++);T1.on('cacheMisses',()=>this.cacheMisses++);const U1=setInterval(()=>reset(this),T1.options.rollingCountTimeout);if(typeof U1.unref==='function')U1.unref();}}function reset(V1){V1.failures=0;V1.fallbacks=0;V1.successes=0;V1.rejects=0;V1.fires=0;V1.timeouts=0;V1.cacheHits=0;V1.cacheMisses=0;}Q1.exports=R1=Status;},{}],6:[function(W1,X1,Y1){function EventEmitter(){this._events=this._events||{};this._maxListeners=this._maxListeners||void 0;}X1.exports=EventEmitter;EventEmitter.EventEmitter=EventEmitter;EventEmitter.prototype._events=void 0;EventEmitter.prototype._maxListeners=void 0;EventEmitter.defaultMaxListeners=10;EventEmitter.prototype.setMaxListeners=function(n){if(!isNumber(n)||n<0||isNaN(n))throw TypeError('n must be a positive number');this._maxListeners=n;return this;};EventEmitter.prototype.emit=function(Z1){var er,b2,c2,d2,i,e2;if(!this._events)this._events={};if(Z1==='error'){if(!this._events.error||isObject(this._events.error)&&!this._events.error.length){er=arguments[1];if(er instanceof Error){throw er;}else{var f2=new Error('Uncaught, unspecified "error" event. ('+er+')');f2.context=er;throw f2;}}}b2=this._events[Z1];if(isUndefined(b2))return!1;if(isFunction(b2)){switch(arguments.length){case 1:b2.call(this);break;case 2:b2.call(this,arguments[1]);break;case 3:b2.call(this,arguments[1],arguments[2]);break;default:d2=Array.prototype.slice.call(arguments,1);b2.apply(this,d2);}}else if(isObject(b2)){d2=Array.prototype.slice.call(arguments,1);e2=b2.slice();c2=e2.length;for(i=0;i<c2;i++)e2[i].apply(this,d2);}return!0;};EventEmitter.prototype.addListener=function(g2,h2){var m;if(!isFunction(h2))throw TypeError('listener must be a function');if(!this._events)this._events={};if(this._events.newListener)this.emit('newListener',g2,isFunction(h2.listener)?h2.listener:h2);if(!this._events[g2])this._events[g2]=h2;else if(isObject(this._events[g2]))this._events[g2].push(h2);else this._events[g2]=[this._events[g2],h2];if(isObject(this._events[g2])&&!this._events[g2].warned){if(!isUndefined(this._maxListeners)){m=this._maxListeners;}else{m=EventEmitter.defaultMaxListeners;}if(m&&m>0&&this._events[g2].length>m){this._events[g2].warned=!0;console.error('(node) warning: possible EventEmitter memory '+'leak detected. %d listeners added. '+'Use emitter.setMaxListeners() to increase limit.',this._events[g2].length);if(typeof console.trace==='function'){console.trace();}}}return this;};EventEmitter.prototype.on=EventEmitter.prototype.addListener;EventEmitter.prototype.once=function(i2,j2){if(!isFunction(j2))throw TypeError('listener must be a function');var k2=!1;function g(){this.removeListener(i2,g);if(!k2){k2=!0;j2.apply(this,arguments);}}g.listener=j2;this.on(i2,g);return this;};EventEmitter.prototype.removeListener=function(l2,m2){var n2,o2,p2,i;if(!isFunction(m2))throw TypeError('listener must be a function');if(!this._events||!this._events[l2])return this;n2=this._events[l2];p2=n2.length;o2=-1;if(n2===m2||isFunction(n2.listener)&&n2.listener===m2){delete this._events[l2];if(this._events.removeListener)this.emit('removeListener',l2,m2);}else if(isObject(n2)){for(i=p2;i-->0;){if(n2[i]===m2||n2[i].listener&&n2[i].listener===m2){o2=i;break;}}if(o2<0)return this;if(n2.length===1){n2.length=0;delete this._events[l2];}else{n2.splice(o2,1);}if(this._events.removeListener)this.emit('removeListener',l2,m2);}return this;};EventEmitter.prototype.removeAllListeners=function(q2){var r2,s2;if(!this._events)return this;if(!this._events.removeListener){if(arguments.length===0)this._events={};else if(this._events[q2])delete this._events[q2];return this;}if(arguments.length===0){for(r2 in this._events){if(r2==='removeListener')continue;this.removeAllListeners(r2);}this.removeAllListeners('removeListener');this._events={};return this;}s2=this._events[q2];if(isFunction(s2)){this.removeListener(q2,s2);}else if(s2){while(s2.length)this.removeListener(q2,s2[s2.length-1]);}delete this._events[q2];return this;};EventEmitter.prototype.listeners=function(t2){var u2;if(!this._events||!this._events[t2])u2=[];else if(isFunction(this._events[t2]))u2=[this._events[t2]];else u2=this._events[t2].slice();return u2;};EventEmitter.prototype.listenerCount=function(v2){if(this._events){var w2=this._events[v2];if(isFunction(w2))return 1;else if(w2)return w2.length;}return 0;};EventEmitter.listenerCount=function(x2,y2){return x2.listenerCount(y2);};function isFunction(z2){return typeof z2==='function';}function isNumber(A2){return typeof A2==='number';}function isObject(B2){return typeof B2==='object'&&B2!==null;}function isUndefined(C2){return C2===void 0;}},{}],7:[function(D2,E2,F2){(function(G2){(function(){'use strict';var H2=typeof G2==='object'&&G2&&G2.Object===Object&&G2,I2=H2||Function('return this')();const J2=0,K2=1,L2=2,M2=Symbol('handlers'),N2=Symbol('queue'),O2=Symbol('state'),P2=Symbol('value');class FidelityPromise{constructor(fn){this[N2]=[];this[M2]=new Handlers();this[O2]=J2;this[P2]=void 0;const R2=typeof fn;if(R2==='function'){tryFunction(fn,this);}else if(R2!=='undefined'){resolvePromise(this,fn);}}get state(){return this[O2];}get value(){return this[P2];}then(S2,T2){const U2=new FidelityPromise();if(typeof S2==='function'){U2[M2].fulfill=S2;}if(typeof T2==='function'){U2[M2].reject=T2;}this[N2].push(U2);process(this);return U2;}catch(V2){return this.then(null,V2);}static promise(fn){console.error('Fidelity.promise() is deprecated. Use `new Fidelity.Promise()`.');return new FidelityPromise(fn);}static deferred(){let X2,Y2;const p=new FidelityPromise((Z2,a3)=>{X2=Z2;Y2=a3;});return{promise:p,resolve:b3=>X2(b3),reject:c3=>Y2(c3)};}static resolve(d3){if(d3&&d3.then)return d3;switch(d3){case null:return q3;case!0:return o3;case!1:return p3;case 0:return r3;case'':return s3;}const p=new FidelityPromise();p[O2]=K2;p[P2]=d3;return p;}static reject(e3){const p=new FidelityPromise();p[O2]=L2;p[P2]=e3;return p;}static all(){const f3=[],g3=Array.from(arguments).reduce((a,b)=>a.concat(b),[]),h3=g3.reduce((i3,p)=>i3.then(()=>p).then(r=>f3.push(r)),Promise.resolve(null));return h3.then(_=>f3);}static race(){const j3=Array.from(arguments).reduce((a,b)=>a.concat(b),[]);return new FidelityPromise((k3,l3)=>{j3.forEach(p=>p.then(k3).catch(l3));});}}FidelityPromise.PENDING=J2;FidelityPromise.FULFILLED=K2;FidelityPromise.REJECTED=L2;class Handlers{constructor(){this.fulfill=null;this.reject=null;}}const m3=(()=>{if(I2.process&&typeof I2.process.nextTick==='function'){return I2.process.nextTick;}else if(typeof I2.setImmediate==='function'){return I2.setImmediate;}else if(typeof I2.setTimeout==='function'){return(f,p)=>I2.setTimeout(f,0,p);}else{console.error('No nextTick. How we gonna do this?');return(f,p)=>f.call(this,p);}})();function exportModule(n3){if(typeof E2==='object'&&E2.exports){E2.exports=n3;}else{I2[n3.name]=n3;}}const o3=new FidelityPromise(!0),p3=new FidelityPromise(!1),q3=new FidelityPromise(null),r3=new FidelityPromise(0),s3=new FidelityPromise('');function tryFunction(fn,u3){try{fn(v=>resolvePromise(u3,v),r=>transition(u3,L2,r));}catch(e){transition(u3,L2,e);}}function resolvePromise(p,x){if(x===p){transition(p,L2,new TypeError('The promise and its value are the same.'));return;}const v3=typeof x;if(x&&(v3==='function'||v3==='object')){let w3=!1;try{const x3=x.then;if(x3&&typeof x3==='function'){x3.call(x,y=>{if(!w3){resolvePromise(p,y);w3=!0;}},r=>{if(!w3){transition(p,L2,r);w3=!0;}});}else{transition(p,K2,x);w3=!0;}}catch(e){if(!w3){transition(p,L2,e);w3=!0;}}}else{transition(p,K2,x);}}function process(p){if(p[O2]===J2)return;m3(processNextTick,p);return p;}function processNextTick(p){let y3,qp;while(p[N2].length){qp=p[N2].shift();if(p[O2]===K2){y3=qp[M2].fulfill||(v=>v);}else if(p[O2]===L2){y3=qp[M2].reject||(r=>{throw r;});}try{resolvePromise(qp,y3(p[P2]));}catch(e){transition(qp,L2,e);continue;}}}function transition(p,A3,B3){if(p[O2]===A3||p[O2]!==J2)return;p[O2]=A3;p[P2]=B3;return process(p);}exportModule(FidelityPromise);}).call(this);}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});},{}],8:[function(C3,D3,E3){var F3=D3.exports={},G3,H3;function defaultSetTimout(){throw new Error('setTimeout has not been defined');}function defaultClearTimeout(){throw new Error('clearTimeout has not been defined');}(function(){try{if(typeof setTimeout==='function'){G3=setTimeout;}else{G3=defaultSetTimout;}}catch(e){G3=defaultSetTimout;}try{if(typeof clearTimeout==='function'){H3=clearTimeout;}else{H3=defaultClearTimeout;}}catch(e){H3=defaultClearTimeout;}})();function runTimeout(I3){if(G3===setTimeout){return setTimeout(I3,0);}if((G3===defaultSetTimout||!G3)&&setTimeout){G3=setTimeout;return setTimeout(I3,0);}try{return G3(I3,0);}catch(e){try{return G3.call(null,I3,0);}catch(e){return G3.call(this,I3,0);}}}function runClearTimeout(J3){if(H3===clearTimeout){return clearTimeout(J3);}if((H3===defaultClearTimeout||!H3)&&clearTimeout){H3=clearTimeout;return clearTimeout(J3);}try{return H3(J3);}catch(e){try{return H3.call(null,J3);}catch(e){return H3.call(this,J3);}}}var K3=[],L3=!1,M3,N3=-1;function cleanUpNextTick(){if(!L3||!M3){return;}L3=!1;if(M3.length){K3=M3.concat(K3);}else{N3=-1;}if(K3.length){drainQueue();}}function drainQueue(){if(L3){return;}var O3=runTimeout(cleanUpNextTick);L3=!0;var P3=K3.length;while(P3){M3=K3;K3=[];while(++N3<P3){if(M3){M3[N3].run();}}N3=-1;P3=K3.length;}M3=null;L3=!1;runClearTimeout(O3);}F3.nextTick=function(Q3){var R3=new Array(arguments.length-1);if(arguments.length>1){for(var i=1;i<arguments.length;i++){R3[i-1]=arguments[i];}}K3.push(new Item(Q3,R3));if(K3.length===1&&!L3){runTimeout(drainQueue);}};function Item(S3,T3){this.fun=S3;this.array=T3;}Item.prototype.run=function(){this.fun.apply(null,this.array);};F3.title='browser';F3.browser=!0;F3.env={};F3.argv=[];F3.version='';F3.versions={};function noop(){}F3.on=noop;F3.addListener=noop;F3.once=noop;F3.off=noop;F3.removeListener=noop;F3.removeAllListeners=noop;F3.emit=noop;F3.binding=function(U3){throw new Error('process.binding is not supported');};F3.cwd=function(){return'/';};F3.chdir=function(V3){throw new Error('process.chdir is not supported');};F3.umask=function(){return 0;};},{}]},{},[1,2,3,4,5]); | ||
@@ -65,3 +65,3 @@ (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
}).call(this,require('_process')) | ||
},{"./lib/circuit":2,"./lib/promisify":3,"_process":7,"fidelity":6}],2:[function(require,module,exports){ | ||
},{"./lib/circuit":2,"./lib/promisify":4,"_process":8,"fidelity":7}],2:[function(require,module,exports){ | ||
'use strict'; | ||
@@ -80,2 +80,4 @@ | ||
const STATUS = Symbol('status'); | ||
const NAME = Symbol('name'); | ||
const CACHE = new WeakMap(); | ||
@@ -96,2 +98,5 @@ /** | ||
* the breaker to `halfOpen` state, and trying the action again. | ||
* @param 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 | ||
* @fires CircuitBreaker#halfOpen | ||
@@ -103,2 +108,3 @@ */ | ||
this.options = options; | ||
this.options.rollingCountTimeout = options.rollingCountTimeout || 10000; | ||
this.Promise = options.Promise; | ||
@@ -110,2 +116,3 @@ this[STATUS] = new Status(this); | ||
this[NUM_FAILURES] = 0; | ||
this[NAME] = options.name || action.name || nextName(); | ||
@@ -135,2 +142,5 @@ if (typeof action !== 'function') this.action = () => this.Promise.resolve(action); | ||
this.on('success', () => this.close()); | ||
if (this.options.cache) { | ||
CACHE.set(this, undefined); | ||
} | ||
} | ||
@@ -174,2 +184,6 @@ | ||
get name () { | ||
return this[NAME]; | ||
} | ||
/** | ||
@@ -240,2 +254,18 @@ * True if the circuit is currently closed. False otherwise. | ||
fire () { | ||
if (CACHE.get(this) !== undefined) { | ||
/** | ||
* Emitted when the circuit breaker is using the cache | ||
* @event CircuitBreaker#cacheHits | ||
*/ | ||
this.emit('cacheHits'); | ||
return CACHE.get(this); | ||
} else if (this.options.cache) { | ||
/** | ||
* Emitted when the circuit breaker is not using the cache but | ||
* the cache option is enabled. | ||
* @event CircuitBreaker#cacheHits | ||
*/ | ||
this.emit('cacheMisses'); | ||
} | ||
const args = Array.prototype.slice.call(arguments); | ||
@@ -254,3 +284,4 @@ /** | ||
this.emit('reject', new Error('Breaker is open')); | ||
return fallback(this, args) || fail(this, 'Breaker is open', args); | ||
const failure = fail(this, 'Breaker is open', args); | ||
return fallback(this, 'Breaker is open', args) || failure; | ||
} | ||
@@ -261,16 +292,16 @@ this[PENDING_CLOSE] = this.halfOpen; | ||
let timeoutError = false; | ||
try { | ||
return new this.Promise((resolve, reject) => { | ||
timeout = setTimeout( | ||
() => { | ||
timeoutError = true; | ||
const error = new Error(`Timed out after ${this.options.timeout}ms`); | ||
/** | ||
* Emitted when the circuit breaker action takes longer than `options.timeout` | ||
* @event CircuitBreaker#timeout | ||
*/ | ||
this.emit('timeout', error); | ||
resolve(fallback(this, args) || fail(this, error, args)); | ||
}, this.options.timeout); | ||
return new this.Promise((resolve, reject) => { | ||
timeout = setTimeout( | ||
() => { | ||
timeoutError = true; | ||
const error = new Error(`Timed out after ${this.options.timeout}ms`); | ||
/** | ||
* Emitted when the circuit breaker action takes longer than `options.timeout` | ||
* @event CircuitBreaker#timeout | ||
*/ | ||
this.emit('timeout', error); | ||
resolve(fallback(this, error, args) || fail(this, error, args)); | ||
}, this.options.timeout); | ||
try { | ||
const result = this.action.apply(this.action, args); | ||
@@ -290,21 +321,33 @@ const promise = (typeof result.then === 'function') | ||
resolve(result); | ||
if (this.options.cache) { | ||
CACHE.set(this, promise); | ||
} | ||
clearTimeout(timeout); | ||
} | ||
}) | ||
.catch((error) => { | ||
clearTimeout(timeout); | ||
const fb = fallback(this, args); | ||
if (fb) return resolve(fb); | ||
fail(this, error, args); | ||
reject(error); | ||
}); | ||
}); | ||
} catch (error) { | ||
clearTimeout(timeout); | ||
return fallback(this, args) || fail(this, error, args); | ||
} | ||
.catch((error) => | ||
handleError(error, this, timeout, args, resolve, reject)); | ||
} catch (error) { | ||
handleError(error, this, timeout, args, resolve, reject); | ||
} | ||
}); | ||
} | ||
/** | ||
* Clears the cache of this {@link CircuitBreaker} | ||
*/ | ||
clearCache () { | ||
CACHE.set(this, undefined); | ||
} | ||
} | ||
function fallback (circuit, args) { | ||
function handleError (error, circuit, timeout, args, resolve, reject) { | ||
clearTimeout(timeout); | ||
fail(circuit, error, args); | ||
const fb = fallback(circuit, error, args); | ||
if (fb) resolve(fb); | ||
else reject(error); | ||
} | ||
function fallback (circuit, err, args) { | ||
if (circuit[FALLBACK_FUNCTION]) { | ||
@@ -317,3 +360,3 @@ return new circuit.Promise((resolve, reject) => { | ||
*/ | ||
circuit.emit('fallback', result); | ||
circuit.emit('fallback', result, err); | ||
resolve(result); | ||
@@ -336,11 +379,89 @@ }); | ||
} | ||
return circuit.Promise.reject.apply(null, [err]); | ||
} | ||
// http://stackoverflow.com/a/2117523 | ||
const nextName = () => | ||
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { | ||
const r = Math.random() * 16 | 0; | ||
const v = c === 'x' ? r : (r & 0x3 | 0x8); | ||
return v.toString(16); | ||
}); | ||
module.exports = exports = CircuitBreaker; | ||
},{"./status":4,"events":5}],3:[function(require,module,exports){ | ||
},{"./status":5,"events":6}],3:[function(require,module,exports){ | ||
'use strict'; | ||
function getStreamData (circuit, name, group) { | ||
console.log(circuit.status, circuit.opened, circuit.halfOpen, circuit.closed); | ||
const json = {}; | ||
json.type = 'HystrixCommand'; | ||
json.name = name; | ||
json.group = group; | ||
json.currentTime = new Date(); | ||
json.isCircuitBreakerOpen = circuit.opened || circuit.halfOpen; | ||
json.errorPercentage = circuit.status.fires === 0 ? 0 : (circuit.status.failures / circuit.status.fires) * 100; | ||
json.errorCount = circuit.status.failures; | ||
json.requestCount = circuit.status.fires; | ||
json.rollingCountBadRequests = circuit.status.failures; | ||
json.rollingCountCollapsedRequests = 0; | ||
json.rollingCountEmit = 0; | ||
json.rollingCountExceptionsThrown = 0; | ||
json.rollingCountFailure = circuit.status.failures; | ||
json.rollingCountFallbackEmit = circuit.status.fallbacks; | ||
json.rollingCountFallbackFailure = 0; | ||
json.rollingCountFallbackMissing = 0; | ||
json.rollingCountFallbackRejection = 0; | ||
json.rollingCountFallbackSuccess = 0; | ||
json.rollingCountResponsesFromCache = 0; | ||
json.rollingCountSemaphoreRejected = circuit.status.rejects; | ||
json.rollingCountShortCircuited = circuit.status.rejects; | ||
json.rollingCountSuccess = circuit.status.successes; | ||
json.rollingCountThreadPoolRejected = 0; | ||
json.rollingCountTimeout = circuit.status.timeouts; | ||
json.currentConcurrentExecutionCount = 0; | ||
json.rollingMaxConcurrentExecutionCount = 0; | ||
json.latencyExecute_mean = 0; | ||
json.latencyExecute = { | ||
'0': 0, | ||
'25': 0, | ||
'50': 0, | ||
'75': 0, | ||
'90': 0, | ||
'95': 0, | ||
'99': 0, | ||
'99.5': 0, | ||
'100': 0 | ||
}; | ||
json.latencyTotal_mean = 0; | ||
json.latencyTotal = { '0': 0, '25': 0, '50': 0, '75': 0, '90': 0, '95': 0, '99': 0, '99.5': 0, '100': 0 }; | ||
json.propertyValue_circuitBreakerRequestVolumeThreshold = 5; | ||
json.propertyValue_circuitBreakerSleepWindowInMilliseconds = 5000; | ||
json.propertyValue_circuitBreakerErrorThresholdPercentage = 50; | ||
json.propertyValue_circuitBreakerForceOpen = false; | ||
json.propertyValue_circuitBreakerForceClosed = false; | ||
json.propertyValue_circuitBreakerEnabled = true; | ||
json.propertyValue_executionIsolationStrategy = 'THREAD'; | ||
json.propertyValue_executionIsolationThreadTimeoutInMilliseconds = 300; | ||
json.propertyValue_executionTimeoutInMilliseconds = 300; | ||
json.propertyValue_executionIsolationThreadInterruptOnTimeout = true; | ||
json.propertyValue_executionIsolationThreadPoolKeyOverride = null; | ||
json.propertyValue_executionIsolationSemaphoreMaxConcurrentRequests = 10; | ||
json.propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests = 10; | ||
json.propertyValue_metricsRollingStatisticalWindowInMilliseconds = 10000; | ||
json.propertyValue_requestCacheEnabled = true; | ||
json.propertyValue_requestLogEnabled = true; | ||
json.reportingHosts = 1; | ||
return JSON.stringify(json); | ||
} | ||
module.exports = exports = { | ||
getStreamData | ||
}; | ||
},{}],4:[function(require,module,exports){ | ||
'use strict'; | ||
const Fidelity = require('fidelity'); | ||
@@ -362,3 +483,3 @@ | ||
},{"fidelity":6}],4:[function(require,module,exports){ | ||
},{"fidelity":7}],5:[function(require,module,exports){ | ||
'use strict'; | ||
@@ -375,26 +496,3 @@ | ||
constructor (circuit) { | ||
/** | ||
* The number of times the breaker's action has failed | ||
*/ | ||
this.failures = 0; | ||
/** | ||
* The number of times a fallback function has been executed | ||
*/ | ||
this.fallbacks = 0; | ||
/** | ||
* The number of times the action for this breaker executed successfully | ||
*/ | ||
this.successes = 0; | ||
/** | ||
* The number of times this breaker been rejected because it was fired, but in the open state. | ||
*/ | ||
this.rejects = 0; | ||
/** | ||
* The number of times this circuit breaker has been fired | ||
*/ | ||
this.fires = 0; | ||
/** | ||
* The number of times this circuit breaker has timed out | ||
*/ | ||
this.timeouts = 0; | ||
reset(this); | ||
this[CIRCUIT_BREAKER] = circuit; | ||
@@ -407,8 +505,48 @@ circuit.on('success', () => this.successes++); | ||
circuit.on('reject', () => this.rejects++); | ||
circuit.on('cacheHits', () => this.cacheHits++); | ||
circuit.on('cacheMisses', () => this.cacheMisses++); | ||
const interval = setInterval( | ||
() => reset(this), circuit.options.rollingCountTimeout); | ||
if (typeof interval.unref === 'function') interval.unref(); | ||
} | ||
} | ||
function reset (status) { | ||
/** | ||
* The number of times the breaker's action has failed | ||
*/ | ||
status.failures = 0; | ||
/** | ||
* The number of times a fallback function has been executed | ||
*/ | ||
status.fallbacks = 0; | ||
/** | ||
* The number of times the action for this breaker executed successfully | ||
*/ | ||
status.successes = 0; | ||
/** | ||
* The number of times this breaker been rejected because it was fired, but in the open state. | ||
*/ | ||
status.rejects = 0; | ||
/** | ||
* The number of times this circuit breaker has been fired | ||
*/ | ||
status.fires = 0; | ||
/** | ||
* The number of times this circuit breaker has timed out | ||
*/ | ||
status.timeouts = 0; | ||
/** | ||
* The number of the cache hits | ||
*/ | ||
status.cacheHits = 0; | ||
/** | ||
* The number of the cache misses | ||
*/ | ||
status.cacheMisses = 0; | ||
} | ||
module.exports = exports = Status; | ||
},{}],5:[function(require,module,exports){ | ||
},{}],6:[function(require,module,exports){ | ||
// Copyright Joyent, Inc. and other Node contributors. | ||
@@ -717,3 +855,3 @@ // | ||
},{}],6:[function(require,module,exports){ | ||
},{}],7:[function(require,module,exports){ | ||
(function (global){ | ||
@@ -1041,3 +1179,3 @@ (function () { | ||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | ||
},{}],7:[function(require,module,exports){ | ||
},{}],8:[function(require,module,exports){ | ||
// shim for using process in browser | ||
@@ -1224,2 +1362,2 @@ var process = module.exports = {}; | ||
},{}]},{},[1,2,3,4]); | ||
},{}]},{},[1,2,3,4,5]); |
@@ -14,2 +14,4 @@ 'use strict'; | ||
const STATUS = Symbol('status'); | ||
const NAME = Symbol('name'); | ||
const CACHE = new WeakMap(); | ||
@@ -30,2 +32,5 @@ /** | ||
* the breaker to `halfOpen` state, and trying the action again. | ||
* @param 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 | ||
* @fires CircuitBreaker#halfOpen | ||
@@ -37,2 +42,3 @@ */ | ||
this.options = options; | ||
this.options.rollingCountTimeout = options.rollingCountTimeout || 10000; | ||
this.Promise = options.Promise; | ||
@@ -44,2 +50,3 @@ this[STATUS] = new Status(this); | ||
this[NUM_FAILURES] = 0; | ||
this[NAME] = options.name || action.name || nextName(); | ||
@@ -69,2 +76,5 @@ if (typeof action !== 'function') this.action = () => this.Promise.resolve(action); | ||
this.on('success', () => this.close()); | ||
if (this.options.cache) { | ||
CACHE.set(this, undefined); | ||
} | ||
} | ||
@@ -108,2 +118,6 @@ | ||
get name () { | ||
return this[NAME]; | ||
} | ||
/** | ||
@@ -174,2 +188,18 @@ * True if the circuit is currently closed. False otherwise. | ||
fire () { | ||
if (CACHE.get(this) !== undefined) { | ||
/** | ||
* Emitted when the circuit breaker is using the cache | ||
* @event CircuitBreaker#cacheHits | ||
*/ | ||
this.emit('cacheHits'); | ||
return CACHE.get(this); | ||
} else if (this.options.cache) { | ||
/** | ||
* Emitted when the circuit breaker is not using the cache but | ||
* the cache option is enabled. | ||
* @event CircuitBreaker#cacheHits | ||
*/ | ||
this.emit('cacheMisses'); | ||
} | ||
const args = Array.prototype.slice.call(arguments); | ||
@@ -188,3 +218,4 @@ /** | ||
this.emit('reject', new Error('Breaker is open')); | ||
return fallback(this, args) || fail(this, 'Breaker is open', args); | ||
const failure = fail(this, 'Breaker is open', args); | ||
return fallback(this, 'Breaker is open', args) || failure; | ||
} | ||
@@ -195,16 +226,16 @@ this[PENDING_CLOSE] = this.halfOpen; | ||
let timeoutError = false; | ||
try { | ||
return new this.Promise((resolve, reject) => { | ||
timeout = setTimeout( | ||
() => { | ||
timeoutError = true; | ||
const error = new Error(`Timed out after ${this.options.timeout}ms`); | ||
/** | ||
* Emitted when the circuit breaker action takes longer than `options.timeout` | ||
* @event CircuitBreaker#timeout | ||
*/ | ||
this.emit('timeout', error); | ||
resolve(fallback(this, args) || fail(this, error, args)); | ||
}, this.options.timeout); | ||
return new this.Promise((resolve, reject) => { | ||
timeout = setTimeout( | ||
() => { | ||
timeoutError = true; | ||
const error = new Error(`Timed out after ${this.options.timeout}ms`); | ||
/** | ||
* Emitted when the circuit breaker action takes longer than `options.timeout` | ||
* @event CircuitBreaker#timeout | ||
*/ | ||
this.emit('timeout', error); | ||
resolve(fallback(this, error, args) || fail(this, error, args)); | ||
}, this.options.timeout); | ||
try { | ||
const result = this.action.apply(this.action, args); | ||
@@ -224,21 +255,33 @@ const promise = (typeof result.then === 'function') | ||
resolve(result); | ||
if (this.options.cache) { | ||
CACHE.set(this, promise); | ||
} | ||
clearTimeout(timeout); | ||
} | ||
}) | ||
.catch((error) => { | ||
clearTimeout(timeout); | ||
const fb = fallback(this, args); | ||
if (fb) return resolve(fb); | ||
fail(this, error, args); | ||
reject(error); | ||
}); | ||
}); | ||
} catch (error) { | ||
clearTimeout(timeout); | ||
return fallback(this, args) || fail(this, error, args); | ||
} | ||
.catch((error) => | ||
handleError(error, this, timeout, args, resolve, reject)); | ||
} catch (error) { | ||
handleError(error, this, timeout, args, resolve, reject); | ||
} | ||
}); | ||
} | ||
/** | ||
* Clears the cache of this {@link CircuitBreaker} | ||
*/ | ||
clearCache () { | ||
CACHE.set(this, undefined); | ||
} | ||
} | ||
function fallback (circuit, args) { | ||
function handleError (error, circuit, timeout, args, resolve, reject) { | ||
clearTimeout(timeout); | ||
fail(circuit, error, args); | ||
const fb = fallback(circuit, error, args); | ||
if (fb) resolve(fb); | ||
else reject(error); | ||
} | ||
function fallback (circuit, err, args) { | ||
if (circuit[FALLBACK_FUNCTION]) { | ||
@@ -251,3 +294,3 @@ return new circuit.Promise((resolve, reject) => { | ||
*/ | ||
circuit.emit('fallback', result); | ||
circuit.emit('fallback', result, err); | ||
resolve(result); | ||
@@ -270,6 +313,13 @@ }); | ||
} | ||
return circuit.Promise.reject.apply(null, [err]); | ||
} | ||
// http://stackoverflow.com/a/2117523 | ||
const nextName = () => | ||
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { | ||
const r = Math.random() * 16 | 0; | ||
const v = c === 'x' ? r : (r & 0x3 | 0x8); | ||
return v.toString(16); | ||
}); | ||
module.exports = exports = CircuitBreaker; |
@@ -12,26 +12,3 @@ 'use strict'; | ||
constructor (circuit) { | ||
/** | ||
* The number of times the breaker's action has failed | ||
*/ | ||
this.failures = 0; | ||
/** | ||
* The number of times a fallback function has been executed | ||
*/ | ||
this.fallbacks = 0; | ||
/** | ||
* The number of times the action for this breaker executed successfully | ||
*/ | ||
this.successes = 0; | ||
/** | ||
* The number of times this breaker been rejected because it was fired, but in the open state. | ||
*/ | ||
this.rejects = 0; | ||
/** | ||
* The number of times this circuit breaker has been fired | ||
*/ | ||
this.fires = 0; | ||
/** | ||
* The number of times this circuit breaker has timed out | ||
*/ | ||
this.timeouts = 0; | ||
reset(this); | ||
this[CIRCUIT_BREAKER] = circuit; | ||
@@ -44,5 +21,45 @@ circuit.on('success', () => this.successes++); | ||
circuit.on('reject', () => this.rejects++); | ||
circuit.on('cacheHits', () => this.cacheHits++); | ||
circuit.on('cacheMisses', () => this.cacheMisses++); | ||
const interval = setInterval( | ||
() => reset(this), circuit.options.rollingCountTimeout); | ||
if (typeof interval.unref === 'function') interval.unref(); | ||
} | ||
} | ||
function reset (status) { | ||
/** | ||
* The number of times the breaker's action has failed | ||
*/ | ||
status.failures = 0; | ||
/** | ||
* The number of times a fallback function has been executed | ||
*/ | ||
status.fallbacks = 0; | ||
/** | ||
* The number of times the action for this breaker executed successfully | ||
*/ | ||
status.successes = 0; | ||
/** | ||
* The number of times this breaker been rejected because it was fired, but in the open state. | ||
*/ | ||
status.rejects = 0; | ||
/** | ||
* The number of times this circuit breaker has been fired | ||
*/ | ||
status.fires = 0; | ||
/** | ||
* The number of times this circuit breaker has timed out | ||
*/ | ||
status.timeouts = 0; | ||
/** | ||
* The number of the cache hits | ||
*/ | ||
status.cacheHits = 0; | ||
/** | ||
* The number of the cache misses | ||
*/ | ||
status.cacheMisses = 0; | ||
} | ||
module.exports = exports = Status; |
{ | ||
"name": "opossum", | ||
"version": "0.5.1", | ||
"version": "0.6.0", | ||
"author": "Red Hat, Inc.", | ||
@@ -46,3 +46,3 @@ "license": "Apache-2.0", | ||
"babel-plugin-transform-mangle-names": "~2.1.2", | ||
"babel-plugin-transform-merge-sibling-variables": "6.8.1", | ||
"babel-plugin-transform-merge-sibling-variables": "6.8.2", | ||
"babel-plugin-transform-minify-booleans": "~6.8.0", | ||
@@ -52,8 +52,8 @@ "babel-plugin-transform-undefined-to-void": "~6.8.0", | ||
"escompress": "~0.5.0", | ||
"eslint": "~3.15.0", | ||
"eslint": "~3.18.0", | ||
"eslint-config-semistandard": "~7.0.0", | ||
"eslint-config-standard": "~6.2.0", | ||
"eslint-plugin-promise": "~3.4.0", | ||
"eslint-plugin-react": "~6.9.0", | ||
"eslint-plugin-standard": "~2.0.1", | ||
"eslint-config-standard": "~7.0.0", | ||
"eslint-plugin-react": "~6.10.0", | ||
"eslint-plugin-promise": "~3.5.0", | ||
"eslint-plugin-standard": "~2.1.0", | ||
"http-server": "~0.9.0", | ||
@@ -66,6 +66,6 @@ "ink-docstrap": "~1.3.0", | ||
"standard-version": "^4.0.0", | ||
"szero": "^0.8.0", | ||
"szero": "^0.9.0", | ||
"tap-spec": "~4.1.1", | ||
"tape": "~4.6.2", | ||
"tape-run": "~2.2.0" | ||
"tape-run": "~3.0.0" | ||
}, | ||
@@ -72,0 +72,0 @@ "description": "A fail-fast circuit breaker for promises and callbacks", |
90490
12
1743