1.0.2 • Published 2 years ago

@syrf/circuit-breaker v1.0.2

Weekly downloads
-
License
ISC
Repository
github
Last release
2 years ago

circuit-breaker

Circuit breaker library for NodeJs to handle and monitor unstable or slow operation like http request to external service. circuit-breaker breaks internal circuit when average failure has reached a threshold value and provide fallback service while backing off the service so it can recover


States

There are three states of circuit breakers

  • closed : Normal state of the circuit
  • open : State when failure threshold reached, call to the handled service will immediately return CircuitBroken error or execute fallback service
  • half open : State after interval passed and circuit will try to execute service again. if success threshold reached circuit will close. if failure threshold reached again, circuit will open again

Examples

Basic Usage

const Breaker = require('circuit-breaker');

const unstableService = (parameter1, parameter2) => {
  return new Promise((resolve, reject) => {
    //call to an unstable service
    console.log(parameter1, parameter2);
    //will print hello world
  });
};

const breaker = Breaker.create(unstableService)
  .withFailureThreshold(0.3)
  .withSuccessThreshold(0.5);

const parameter1 = 'Hello';
const parameter2 = 'World';
breaker.exec(parameter1, parameter2);

Fallback

const unstableService = (parameter1, parameter2) => {
  return new Promise((resolve, reject) => {
    //call to an unstable service
    reject(new Error('Some Error'));
  });
};

const fallbackService = (parameter1, parameter2) => {
  return new Promise((resolve, reject) => {
    console.log('Fallback ', parameter1, parameter2);
    //will print Fallback hello world
  });
};

const breaker =
  Breaker.create(unstableService).withFallbackService(fallbackService);

const parameter1 = 'Hello';
const parameter2 = 'World';
breaker.exec(parameter1, parameter2);

Intervals

Interval define time span after circuit broke to switch to half open for retries

Fixed Interval

const breaker = Breaker.create(unstableService).withBackoffInterval({
  interval: 10 * 1000,
});

Incremental Interval

const breaker = Breaker.create(unstableService).withBackoffInterval({
  increment: 5 * 1000, //will increase interval by 5s every retry
});

Exponential Interval

Exponential interval will power the interval by the number of retry

const breaker = Breaker.create(unstableService).withBackoffInterval({
  exponentInterval: true,
});

For more real case examples you can check the examples directory

Constructor

circuit breaker accepts two arguments

  • service : function which returns Promise
  • config : configuration object

Configurations

Available configuration options : Config | Type | Default | Description ---|---|---|--- name|string|defaultBrake|name of service. mostly used to identify service on global monitor group |string|defaultGroup|name of service group. mostly used to identify service on global monitor failureThreshold |number|0.5|average failure threshold to trigger circuit to break successThreshold |number|0.5|average success threshold to trigger circuit to recover interval|number|10000|Time interval in milliseconds to back off the service increment|number|0|Time interval increment in milliseconds. incremented when circuit is closed again after half open state exponentInterval|boolean|false|Flag to set interval to exponential if the service keeps on failing. the interval value in second will be powered to number of attempt to connect timeout|number|3000|Max execution time in milliseconds for handled service fallback|method|null|Fallback method expected to return promise bucketSpan|number|1000|time span of a bucket to should remain active bucketCount|number|60|number of buckets to retain in a rolling window statsInterval|number|5000|time interval between stats reporting registerGlobal|boolean|true|specify if circuit breaker should be regitered in global stats

Builder Methods Samples

List of builder methods to ease up configuring circuit breaker

  • static Breaker.create(service)
  • .withFallbackService(serviceFallback)
  • .withFailureThreshold(0.35)
  • .withSuccessThreshold(0.65)
  • .withBackoffInterval({ interval: 1000, increment : 2000, exponential : false })
  • .withBucket({ bucketSpan: 5000, bucketCount : 10 })
  • .withExecutionTimeout(3000)
  • .withStatsInterval(1000)

withBackoffInterval and withBucket accept object as parameter. every field of the object is optional, if value not provided, default value will be used

Methods

MethodArgument(s)ReturnsDescription
static getGlobalStatsN/AglobalStatsReturns global status where all circuit breakers registered
execSame arguments with the registered servicePromiseReturns the same promise as the registered service
onstring,functionN/AStandard EventEmitter listening

Non Breaking Error

When handling service using library like axios, we often get expected error like 400 errors etc. but those kind of error is not considered as breaking errors because the error thrown does not indicate that the service is not working properly. to be able to handle the error just like normal error without opening the circuit NonBreakingError can be thrown.

const restService = () => {
  return new Promise((resolve, reject) => {
    axios
      .get('http://example.com/api')
      .then(resolve)
      .catch((err) => {
        // check if the response is started with 400 (400,401,404 etc)
        if (err?.response?.status?.toString()?.[0] === '4') {
          // throw non breaking error
          reject(new Breaker.NonBreakingError(err?.response));
        } else {
          // this will add failure count and opens circuit eventually
          reject(err);
        }
      });
  });
};

Events

List of events emitted by circuit breaker :

  • exec : Event on service execution start
  • failure : Event on service execution failed
  • success : Event on service execution success
  • timeout : Event on service execution timeout
  • circuitClosed : Event when circuit closed
  • circuitOpen : Event when circuit open
  • circuitHalfOpen : Event when circuit half open
  • stats : Event when circuit sends stats

Stats

Circuit breaker will emit stats event with latest stats data based on statsInterval interval Stats object sample :

{
    name: 'defaultBrake',
    group: 'defaultGroup',
    state: 'CLOSED',
    failureThreshold: 0.5,
    successThreshold: 0.5,
    nextAttempt: 1619424986009,
    retryCount: 0,
    bucketSpan: 1000,
    bucketCount: 60,
    increment: 0,
    exponentInterval: false,
    interval: 10000,
    timeout: 3000,
    stats: {
        avgSuccess: 0.9,
        avgFailure: 0.5,
        failed : 10,
        successful : 90,
        total : 100,
        shortCircuited : 0,
        timedOut : 5,
        avgLatency : 1023
    },

}

Global Stats

Global stats will listen to the stats Event emitted by all registered circuit breaker and push the stats to a readable stream

const globalStats = Breaker.getGlobalStats();
globalStats.stream.on('data', (data) => {
  //handle data
  console.log(data);
});

Development

To develop locally clone the repo and use the following commands :

npm install
npm run test