Package detail

opossum

nodeshift1.3mApache-2.09.0.0

A fail-fast circuit breaker for promises and callbacks

circuit breaker, circuit-breaker, fail-fast, circuit

readme

opossum

Node.js CI Coverage Status Known Vulnerabilities Dependency Status

Opossum is a Node.js circuit breaker that executes asynchronous functions and monitors their execution status. When things start failing, opossum plays dead and fails fast. If you want, you can provide a fallback function to be executed when in the failure state.

For more about the circuit breaker pattern, there are lots of resources on the web - search it! Fowler's blog post is one place to start reading.

Project Info
License: Apache-2.0
Documentation: https://nodeshift.dev/opossum/
Typings: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/opossum
Issue tracker: https://github.com/nodeshift/opossum/issues
Engines: Node.js >= 20

Usage

Let's say you've got an API that depends on something that might fail - a network operation, or disk read, for example. Wrap those functions up in a CircuitBreaker and you have control over your destiny.

const CircuitBreaker = require('opossum');

function asyncFunctionThatCouldFail(x, y) {
  return new Promise((resolve, reject) => {
    // Do something, maybe on the network or a disk
  });
}

const options = {
  timeout: 3000, // If our function takes longer than 3 seconds, trigger a failure
  errorThresholdPercentage: 50, // When 50% of requests fail, trip the circuit
  resetTimeout: 30000 // After 30 seconds, try again.
};
const breaker = new CircuitBreaker(asyncFunctionThatCouldFail, options);

breaker.fire(x, y)
  .then(console.log)
  .catch(console.error);

AbortController support

You can provide an AbortController (https://developer.mozilla.org/en-US/docs/Web/API/AbortController, https://nodejs.org/docs/latest/api/globals.html#globals_class_abortcontroller) for aborting on going request upon reaching Opossum timeout.

const CircuitBreaker = require('opossum');
const http = require('http');

function asyncFunctionThatCouldFail(abortSignal, x, y) {
  return new Promise((resolve, reject) => {
    http.get(
      'http://httpbin.org/delay/10',
      { signal: abortSignal },
      (res) => {
        if(res.statusCode < 300) {
          resolve(res.statusCode);
          return;
        }

        reject(res.statusCode);
      }
    );
  });
}

const abortController = new AbortController();
const options = {
  abortController,
  timeout: 3000, // If our function takes longer than 3 seconds, trigger a failure
};
const breaker = new CircuitBreaker(asyncFunctionThatCouldFail, options);

breaker.fire(abortController.signal)
  .then(console.log)
  .catch(console.error);

Auto Renew AbortController

The autoRenewAbortController option allows the automatic renewal of the AbortController when the circuit breaker transitions into the halfOpen or closed states. This feature ensures that the AbortController can be reused properly for ongoing requests without manual intervention.

const CircuitBreaker = require('opossum');
const http = require('http');

function asyncFunctionThatCouldFail(abortSignal, x, y) {
  return new Promise((resolve, reject) => {
    http.get(
      'http://httpbin.org/delay/10',
      { signal: abortSignal },
      (res) => {
        if(res.statusCode < 300) {
          resolve(res.statusCode);
          return;
        }

        reject(res.statusCode);
      }
    );
  });
}

const abortController = new AbortController();
const options = {
  autoRenewAbortController: true,
  timeout: 3000, // If our function takes longer than 3 seconds, trigger a failure
};
const breaker = new CircuitBreaker(asyncFunctionThatCouldFail, options);

const signal = breaker.getSignal();
breaker.fire(signal)
  .then(console.log)
  .catch(console.error);

Fallback

You can also provide a fallback function that will be executed in the event of failure. To take some action when the fallback is performed, listen for the fallback event.

const breaker = new CircuitBreaker(asyncFunctionThatCouldFail, options);
// if asyncFunctionThatCouldFail starts to fail, firing the breaker
// will trigger our fallback function
breaker.fallback(() => 'Sorry, out of service right now');
breaker.on('fallback', (result) => reportFallbackEvent(result));

Once the circuit has opened, a timeout is set based on options.resetTimeout. When the resetTimeout expires, opossum will enter the halfOpen state. Once in the halfOpen state, the next time the circuit is fired, the circuit's action will be executed again. If successful, the circuit will close and emit the close event. If the action fails or times out, it immediately re-enters the open state.

When a fallback function is triggered, it's considered a failure, and the fallback function will continue to be executed until the breaker is closed.

The fallback function accepts the same parameters as the fire function:

const delay = (delay, a, b, c) =>
  new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, delay);
  });

const breaker = new CircuitBreaker(delay);
breaker.fire(20000, 1, 2, 3);
breaker.fallback((delay, a, b, c) => `Sorry, out of service right now. But your parameters are: ${delay}, ${a}, ${b} and ${c}`);

Breaker State Initialization

There may be times where you will need to initialize the state of a Circuit Breaker. Primary use cases for this are in a serverless environment such as Knative or AWS Lambda, or any container based platform, where the container being deployed is ephemeral.

The toJSON method is a helper function to get the current state and status of a breaker:

const breakerState = breaker.toJSON();

This will return an object that might look similar to this:

{
  state: {
    enabled: true,
    name: 'functionName'
    closed: true,
    open: false,
    halfOpen: false,
    warmUp: false,
    shutdown: false
  },
  status: {
    ...
  }
};

A new circuit breaker instance can be created with this state by passing this object in:

const breaker = new CircuitBreaker({state: state});

Status Initialization

There may also be times where you will need to pre-populate the stats of the Circuit Breaker Status Object. Primary use cases for this are also in a serverless environment such as Knative or AWS Lambda, or any container based platform, where the container being deployed is ephemeral.

Getting the existing cumulative stats for a breaker can be done like this:

const stats = breaker.stats;

stats will be an object that might look similar to this:

{
  failures: 11,
  fallbacks: 0,
  successes: 5,
  rejects: 0,
  fires: 16,
  timeouts: 0,
  cacheHits: 0,
  cacheMisses: 0,
  coalesceCacheHits: 0,
  coalesceCacheMisses: 0,
  semaphoreRejections: 0,
  percentiles: {
    '0': 0,
    '1': 0,
    '0.25': 0,
    '0.5': 0,
    '0.75': 0,
    '0.9': 0,
    '0.95': 0,
    '0.99': 0,
    '0.995': 0
  },
  latencyTimes: [ 0 ],
  latencyMean: 0
}

To then re-import those stats, first create a new Status object with the previous stats and then pass that as an option to the CircuitBreaker constructor:

const statusOptions = {
  stats: {....}
};

const newStatus = CircuitBreaker.newStatus(statusOptions);

const breaker = new CircuitBreaker({status: newStatus});

Browser

Opossum really shines in a browser. You can use it to guard against network failures in your AJAX calls.

We recommend using webpack to bundle your applications, since it does not have the effect of polluting the window object with a global. However, if you need it, you can access a circuitBreaker function in the global namespace by doing something similar to what is shown in the below example.

Here is an example using hapi.js. See the opossum-examples repository for more detail.

Include opossum.js in your HTML file.

<html>
<head>
  <title>My Super App</title>
  <script type='text/javascript' src="/jquery.js"></script>
  <script type='text/javascript' src="/opossum.js"></script>
  <script type='text/javascript' src="/app.js"></script>
<body>
...
</body>
</head>
</html>

In your application, set a route to the file, pointing to node_modules/opossum/dist/opossum-min.js.

// server.js
const server = new Hapi.Server();
server.register(require('inert', (err) => possibleError(err)));
server.route({
  method: 'GET',
  path: '/opossum.js',
  handler: {
    file: {
      path: path.join(__dirname, 'node_modules', 'opossum', 'dist', 'opossum-min.js'),
    }
  }
});

In the browser's global scope will be a CircuitBreaker constructor. Use it to create circuit breakers, guarding against network failures in your REST API calls.

// app.js
const route = 'https://example-service.com/rest/route';
const circuitBreakerOptions = {
  timeout: 500,
  errorThresholdPercentage: 50,
  resetTimeout: 5000
};

const breaker = new CircuitBreaker(() => $.get(route), circuitBreakerOptions);
breaker.fallback(() => `${route} unavailable right now. Try later.`));
breaker.on('success', (result) => $(element).append(JSON.stringify(result)}));

$(() => {
  $('#serviceButton').click(() => breaker.fire().catch((e) => console.error(e)));
});

Events

A CircuitBreaker will emit events for important things that occur. Here are the events you can listen for.

  • fire - emitted when the breaker is fired.
  • reject - emitted when the breaker is open (or halfOpen).
  • timeout - emitted when the breaker action times out.
  • success - emitted when the breaker action completes successfully
  • failure - emitted when the breaker action fails, called with the error
  • open - emitted when the breaker state changes to open
  • close - emitted when the breaker state changes to closed
  • halfOpen - emitted when the breaker state changes to halfOpen
  • fallback - emitted when the breaker has a fallback function and executes it
  • semaphoreLocked - emitted when the breaker is at capacity and cannot execute the request
  • healthCheckFailed - emitted when a user-supplied health check function returns a rejected promise
  • shutdown - emitted when the breaker shuts down

Handling events gives a greater level of control over your application behavior.

const breaker = new CircuitBreaker(() => $.get(route), circuitBreakerOptions);

breaker.fallback(() => ({ body: `${route} unavailable right now. Try later.` }));

breaker.on('success',
  (result) => $(element).append(
    makeNode(`SUCCESS: ${JSON.stringify(result)}`)));

breaker.on('timeout',
  () => $(element).append(
    makeNode(`TIMEOUT: ${route} is taking too long to respond.`)));

breaker.on('reject',
  () => $(element).append(
    makeNode(`REJECTED: The breaker for ${route} is open. Failing fast.`)));

breaker.on('open',
  () => $(element).append(
    makeNode(`OPEN: The breaker for ${route} just opened.`)));

breaker.on('halfOpen',
  () => $(element).append(
    makeNode(`HALF_OPEN: The breaker for ${route} is half open.`)));

breaker.on('close',
  () => $(element).append(
    makeNode(`CLOSE: The breaker for ${route} has closed. Service OK.`)));

breaker.on('fallback',
  (data) => $(element).append(
    makeNode(`FALLBACK: ${JSON.stringify(data)}`)));

Promises vs. Callbacks

The opossum API returns a Promise from CircuitBreaker.fire(). But your circuit action - the async function that might fail - doesn't have to return a promise. You can easily turn Node.js style callback functions into something opossum understands by using the built in Node core utility function util.promisify() .

const fs = require('fs');
const { promisify } = require('util');
const CircuitBreaker = require('opossum');

const readFile = promisify(fs.readFile);
const breaker = new CircuitBreaker(readFile, options);

breaker.fire('./package.json', 'utf-8')
  .then(console.log)
  .catch(console.error);

And just for fun, your circuit doesn't even really have to be a function. Not sure when you'd use this - but you could if you wanted to.

const breaker = new CircuitBreaker('foo', options);

breaker.fire()
  .then(console.log) // logs 'foo'
  .catch(console.error);

Calculating errorThresholdPercentage

The errorThresholdPercentage value is compared to the error rate. That rate is determined by dividing the number of failures by the number of times the circuit has been fired. You can see this comparison here:

// check stats to see if the circuit should be opened
  const stats = circuit.stats;
  if ((stats.fires < circuit.volumeThreshold) && !circuit.halfOpen) return;
  const errorRate = stats.failures / stats.fires * 100;
  if (errorRate > circuit.options.errorThresholdPercentage || circuit.halfOpen) {
    circuit.open();
  }

The numbers for fires and failures come from the stats that are indeed governed by rollingCountTimeout and rollingCountBuckets. The timeout value is the total number of seconds for which the stats are being maintained, and the buckets value is the number of slots in the window. The defaults are 10 seconds and 10 buckets. So, the statistics that are being compared against errorThresholdPercentage are based on 10 samples, one per second over the last 10 seconds.

Example: a circuit is fired 24 times over 10 seconds with a somewhat bursty pattern, failing three times.

| fires: 2 | fires: 1 | fires: 3 | fires: 0 | fires: 9 | fires: 3 | fires: 2 | fires: 0 | fires: 4 | fires: 0 |
| fails: 0 | fails: 0 | fails: 0 | fails: 0 | fails: 0 | fails: 3 | fails: 0 | fails: 0 | fails: 0 | fails: 0 |

The failure rate here is 3/24 or 1/8 or 12.5%. The default error threshold is 50%, so in this case, the circuit would not open. However, if you modified the rollingCountTimeout to 3 seconds, and the rollingCountBuckets to 3 (not recommended), then the stats array might look like these three seconds from above.

| fires: 3 | fires: 2 | fires: 0 |
| fails: 3 | fails: 0 | fails: 0 |

Now, without changing errorThresholdPercentage our circuit will open because our error rate is now 3/5 or 60%. It's tricky to test this stuff because the array of statistics is a rolling count. Every second the oldest bucket is removed and a new one is added, so the totals change constantly in a way that may not be intuitive.

For example, if the first example is shifted right, dropping the first bucket and adding another with fires: 3 the total number of fires now in the stats is not 27 (24+3) but 25 (24-2+3).

The code that is summing the stats samples is here:

  const totals = this[WINDOW].reduce((acc, val) => {
    if (!val) { return acc; }
    Object.keys(acc).forEach(key => {
      if (key !== 'latencyTimes' && key !== 'percentiles') {
        (acc[key] += val[key] || 0);
      }
    });

    if (this.rollingPercentilesEnabled) {
      acc.latencyTimes.push.apply(acc.latencyTimes, val.latencyTimes || []);
    }
    return acc;
  }, bucket());

Coalesce calls

Circuitbreaker offers coalescing your calls. If options.coalesce is set, multiple calls to the circuitbreaker will be handled as one, within the given timeframe (options.coalesceTTL). Performance will improve when rapidly firing the circuitbreaker with the same request, especially on a slower action. This is especially useful if multiple events can trigger the same functions at the same time. Of course, caching has the same function, but will only be effective when the call has been successfully executed once to store the return value. Coalescing and cache can be used at the same time, coalescing calls will always use the internal cache. Accessing cache is done prior to coalescing. When using capacity option, coalescing reduces the capacity used for the CircuitBreaker and will allow higher throughput of the rest of the application without actually firing the CircuitBreaker protected function. The cacheGetKey option is used for coalescing as well.

Finetuning Coalesce behavior

By default, all calls within given timeframe are coalesced, including errors and timeouts. This might be unwanted, as this twarths retry mechanisms etc. To finetune coalesce behavior, use the coalesceResetOn parameter. Some examples:

coalesceResetOn value behavior
error, success, timeout coalescing is reset after every 'done' status, so only concurrent 'running' calls are coalesced. One could consider this the most essential form of coalescing.
error, timeout No error state is being stored for longer than the running call, you might want to start here if you use any retry mechanisms.
error Reset on errors.
timeout Reset on timeouts.
success Reset on success.

You can use any combination of error, success, timeout.

Using CircuitBreaker with Coalescing and fetch.

When using the CircuitBreaker with Coalescing enabled to protect calling external services using the Fetch API, it's important to keep this in mind: The Response interface of the Fetch API does not allow reading the same body multiple times, cloning the Response will not help either as it will delay the reading of the response until the slowest reader is done. To work around this you can either choose to wrap handling of the response (e.g. parsing) in the protected function as well, keep in mind any errors and delays in this process will amount to the error thresholds configured. This might not be suitable for complexer setups. Another option would be to flatten the response and revive it. This might come in handy when working with libraries that expect a Response object. Example below:

const flattenResponse = async (r) => ({
  arrayBuffer: await r.arrayBuffer(),
  init: {
    headers: r.headers,
    ok: r.ok,
    redirected: r.redirected,
    status: r.status,
    statusText: r.statusText,
    type: r.type,
    url: r.url,
  },
});

const reviveResponse = (r) => new Response(r.arrayBuffer, r.init);

Also note, Fetch doesn't fail on HTTP errors (e.g. 50x). If you want to protect your application from calling failing APIs, check the response status and throw errors accordingly.

Typings

Typings are available here.

If you'd like to add them, run npm install @types/opossum in your project.

Metrics

Prometheus

The opossum-prometheus module can be used to produce metrics that are consumable by Prometheus. These metrics include information about the circuit itself, for example how many times it has opened, as well as general Node.js statistics, for example event loop lag.

Hystrix

The opossum-hystrix module can be used to produce metrics that are consumable by the Hystrix Dashboard.

Troubleshooting

You may run into issues related to too many listeners on an EventEmitter like this.

(node:25619) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 10 unpipe listeners added. Use emitter.setMaxListeners() to increase limit
(node:25619) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 drain listeners added. Use emitter.setMaxListeners() to increase limit
(node:25619) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
(node:25619) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 close listeners added. Use emitter.setMaxListeners() to increase limit
(node:25619) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 finish listeners added. Use emitter.setMaxListeners() to increase limit

In some cases, seeing this error might indicate a bug in client code, where many CircuitBreakers are inadvertently being created. But there are legitimate scenarios where this may not be the case. For example, it could just be that you need more than 10 CircuitBreakers in your app. That's ok.

To get around the error, you can set the number of listeners on the stream.

breaker.stats.getHystrixStream().setMaxListeners(100);

Or it could be that you have a large test suite which exercises some code that creates CircuitBreakers and does so repeatedly. If the CircuitBreaker being created is only needed for the duration of the test, use breaker.shutdown() when the circuit is no longer in use to clean up all listeners.

changelog

Changelog

All notable changes to this project will be documented in this file. See standard-version for commit guidelines.

9.0.0 (2025-05-30)

⚠ BREAKING CHANGES

  • remove Node 16 and Node 18 support (#921)

Features

8.5.0 (2025-05-29)

Features

Bug Fixes

  • package.json & package-lock.json to reduce vulnerabilities (#915) (66f2b48)

8.4.0 (2024-11-27)

Features

  • Coalesce reset options, reset coalesce based on result. (error, success, timeout) (#908) (c9782ae)

8.3.1 (2024-11-11)

Bug Fixes

  • Incorrect default value of maxEntries for MemoryCache #904 (#906) (f7abe3f)

8.3.0 (2024-10-28)

Features

  • renewing the AbortController when the circuit enters the 'halfClose' or 'close' state (#892) (2ba3a31)

Bug Fixes

8.2.0 (2024-10-23)

Features

  • coalescing calls + feature: max cache size (#877) (d50c912)
  • upgrade nyc from 15.1.0 to 17.0.0 (#862) (ccf7803)

Bug Fixes

  • package.json & package-lock.json to reduce vulnerabilities (#890) (6cd2895)
  • upgrade tape from 5.7.2 to 5.9.0 (#885) (2896676)

8.1.4 (2024-04-30)

Bug Fixes

8.1.3 (2023-11-06)

Bug Fixes

  • push.apply with an unbounded array leads to stack overflow exceptions. (#830) (2cfb1ae)
  • upgrade tape from 5.6.6 to 5.7.0 (#828) (650807a)

8.1.2 (2023-10-05)

Bug Fixes

  • fix bug where options couldn't be set to zero. (#825) (e6b3b77), closes #824
  • upgrade eslint from 8.44.0 to 8.48.0 (#814) (178294e)
  • upgrade eslint from 8.48.0 to 8.49.0 (#822) (fc5c002)

8.1.1 (2023-09-13)

Bug Fixes

8.1.0 (2023-07-31)

Features

  • add option to disable stats snapshots (#799) (a9c5935)

Bug Fixes

  • package.json & package-lock.json to reduce vulnerabilities (#789) (74a45c5)
  • upgrade eslint from 8.40.0 to 8.43.0 (#790) (fda48ca)
  • upgrade eslint from 8.43.0 to 8.44.0 (#794) (3dffb78)
  • upgrade webpack from 5.82.0 to 5.82.1 (#772) (c84639f)
  • upgrade webpack from 5.82.1 to 5.83.1 (#775) (01443c6)
  • upgrade webpack from 5.83.1 to 5.88.0 (#791) (5296413)
  • upgrade webpack-cli from 5.0.2 to 5.1.4 (#782) (e66ca47)

8.0.1 (2023-05-30)

Bug Fixes

  • Reduce apply() calls to improve call times. (#765) (8d559e4)
  • upgrade eslint from 8.39.0 to 8.40.0 (#766) (197cc6d)

8.0.0 (2023-05-25)

⚠ BREAKING CHANGES

  • remove Node 14 (#762)

Features

Bug Fixes

  • package.json & package-lock.json to reduce vulnerabilities (#737) (6f65ff2)
  • upgrade @babel/core from 7.20.12 to 7.21.0 (#738) (2ab63f4)
  • upgrade @babel/core from 7.20.7 to 7.20.12 (#724) (734e10e)
  • upgrade @babel/core from 7.21.5 to 7.21.8 (#761) (fceb955)
  • upgrade babel-loader from 9.1.0 to 9.1.2 (#723) (10d3294)
  • upgrade eslint from 8.30.0 to 8.31.0 (#721) (7af314b)
  • upgrade eslint from 8.31.0 to 8.32.0 (#729) (d858b11)
  • upgrade eslint from 8.32.0 to 8.33.0 (#733) (5de4b15)
  • upgrade eslint from 8.33.0 to 8.34.0 (#736) (941ba0b)
  • upgrade eslint from 8.34.0 to 8.39.0 (#755) (3c12586)
  • upgrade eslint-plugin-import from 2.26.0 to 2.27.5 (#731) (979b898)
  • upgrade eslint-plugin-n from 15.6.0 to 15.6.1 (#725) (84d94d1)
  • upgrade husky from 8.0.1 to 8.0.3 (#722) (9de3755)
  • upgrade multiple dependencies with Snyk (#759) (053a5a5)
  • upgrade serve from 14.1.2 to 14.2.0 (#732) (3a84d3e)
  • upgrade tape from 5.6.1 to 5.6.3 (#730) (3af33ce)
  • upgrade webpack from 5.76.0 to 5.76.3 (#742) (3f9edea)
  • upgrade webpack from 5.76.3 to 5.82.0 (#760) (529747c)
  • upgrade webpack-cli from 5.0.1 to 5.0.2 (#754) (155d321)

7.1.0 (2023-01-19)

Features

  • enter halfOpen state on reinitialization if required (#720) (f20c63c)
  • upgrade babel-loader from 8.2.5 to 9.1.0 (#714) (2226eb4)
  • upgrade webpack-cli from 4.10.0 to 5.0.1 (#715) (47fd10e)

Bug Fixes

  • package.json & package-lock.json to reduce vulnerabilities (#707) (7376408)
  • upgrade @babel/core from 7.19.3 to 7.19.6 (#695) (3c55164)
  • upgrade @babel/core from 7.19.6 to 7.20.5 (#713) (46e4d63)
  • upgrade @babel/core from 7.20.5 to 7.20.7 (#717) (fe2a93a)
  • upgrade eslint from 8.25.0 to 8.29.0 (#711) (3a59b42)
  • upgrade eslint from 8.29.0 to 8.30.0 (#716) (acd4cd3)
  • upgrade eslint-plugin-n from 15.3.0 to 15.6.0 (#710) (f5297b8)
  • upgrade serve from 14.0.1 to 14.1.2 (#712) (0667152)
  • upgrade webpack from 5.74.0 to 5.75.0 (#705) (99c6b0d)

7.0.1 (2022-11-28)

Bug Fixes

  • upgrade @babel/preset-env from 7.19.3 to 7.19.4 (#691) (26c3ce7)
  • upgrade eslint from 8.14.0 to 8.24.0 (#686) (c030d9c)
  • upgrade eslint from 8.24.0 to 8.25.0 (#690) (8c37e10)
  • upgrade eslint-plugin-n from 15.2.0 to 15.3.0 (#687) (e9f540e)
  • upgrade eslint-plugin-promise from 6.0.1 to 6.1.0 (#692) (fd03739)
  • upgrade multiple dependencies with Snyk (#688) (4c634a4)
  • upgrade util from 0.12.4 to 0.12.5 (#693) (dec7c75)

7.0.0 (2022-10-13)

⚠ BREAKING CHANGES

  • drop Node.js 12 (#664)

Features

  • adds AbortController support (#674) (4b5f9f6)
  • upgrade eslint-config-semistandard from 16.0.0 to 17.0.0 (#667) (dab109b)
  • upgrade husky from 7.0.4 to 8.0.0 (#654) (5807884)
  • upgrade serve from 13.0.4 to 14.0.1 (#677) (3af0318)

Bug Fixes

  • package.json & package-lock.json to reduce vulnerabilities (#672) (00c6b08)
  • upgrade eslint-plugin-promise from 6.0.0 to 6.0.1 (#678) (27e3446)
  • upgrade husky from 8.0.0 to 8.0.1 (#679) (2b24410)
  • upgrade serve from 13.0.2 to 13.0.4 (#666) (9bcbc19)
  • upgrade tape from 5.5.3 to 5.6.0 (#676) (54fc8d0)
  • upgrade tape from 5.6.0 to 5.6.1 (#683) (626038f)

Miscellaneous Chores

6.4.0 (2022-06-13)

Features

  • upgrade eslint-config-semistandard from 15.0.1 to 16.0.0 (#632) (6d96a26)
  • upgrade husky from 6.0.0 to 7.0.4 (#630) (fbaa492)
  • upgrade serve from 11.3.2 to 13.0.2 (#631) (5bbb4a8)

Bug Fixes

  • upgrade @babel/core from 7.17.4 to 7.17.5 (#644) (8a31e72)
  • upgrade @babel/core from 7.17.5 to 7.17.7 (#646) (2eb0e25)
  • upgrade @babel/preset-env from 7.16.10 to 7.16.11 (#637) (20e9379)
  • upgrade babel-loader from 8.2.3 to 8.2.4 (#647) (caf22ee)
  • upgrade eslint-plugin-import from 2.25.4 to 2.26.0 (#649) (60d5f21)
  • upgrade multiple dependencies with Snyk (#636) (3561571)
  • upgrade tape from 5.3.2 to 5.4.0 (#626) (308ff6a)
  • upgrade tape from 5.4.1 to 5.5.0 (#642) (e657ab1)
  • upgrade webpack-cli from 4.9.1 to 4.9.2 (#639) (3d28b3d)

6.3.0 (2022-01-10)

Features

  • using semistandard and fixed some typos (#617) (7506923)

Bug Fixes

  • breaker should emit a shutdown event when it is shutdown (#625) (ea4d058), closes #620
  • upgrade @babel/core from 7.15.4 to 7.15.5 (#604) (709530d)
  • upgrade @babel/core from 7.16.0 to 7.16.5 (#622) (43edde6)
  • upgrade @babel/preset-env from 7.15.4 to 7.15.6 (#605) (eb1d279)
  • upgrade @babel/preset-env from 7.16.0 to 7.16.5 (#623) (b875a23)
  • upgrade babel-loader from 8.2.2 to 8.2.3 (#611) (dc31373)
  • upgrade eslint-plugin-import from 2.24.1 to 2.24.2 (#602) (940d3f6)
  • upgrade eslint-plugin-import from 2.24.2 to 2.25.1 (#608) (f827090)
  • upgrade eslint-plugin-import from 2.25.1 to 2.25.2 (#609) (c589ad0)
  • upgrade eslint-plugin-import from 2.25.2 to 2.25.3 (#614) (2084fcc)
  • upgrade eslint-plugin-promise from 5.1.0 to 5.1.1 (#619) (0139be6)
  • upgrade eslint-plugin-promise from 5.1.1 to 5.2.0 (#621) (a2d11b8)
  • upgrade multiple dependencies with Snyk (#603) (ed3fe4f)
  • upgrade multiple dependencies with Snyk (#606) (0385cbd)
  • upgrade multiple dependencies with Snyk (#612) (78982f8)
  • upgrade tape from 5.2.2 to 5.3.1 (#599) (54b2a64)
  • upgrade tape from 5.3.1 to 5.3.2 (#616) (42f21ed)
  • upgrade webpack-cli from 4.7.2 to 4.8.0 (#600) (09744be)
  • upgrade webpack-cli from 4.8.0 to 4.9.0 (#607) (ebadc43)
  • upgrade webpack-cli from 4.9.0 to 4.9.1 (#610) (b390eb1)

6.2.1 (2021-08-23)

Bug Fixes

  • @babel/core, @babel/preset-env (#582) (b5291ac)
  • upgrade coveralls from 3.1.0 to 3.1.1 (#590) (211dffa)
  • upgrade documentation from 13.1.1 to 13.2.5 (#583) (b9d7bc2)
  • upgrade eslint from 7.24.0 to 7.29.0 (#585) (c4570f8)
  • upgrade eslint from 7.29.0 to 7.30.0 (#592) (2747b82)
  • upgrade eslint from 7.30.0 to 7.31.0 (#594) (536b312)
  • upgrade eslint from 7.31.0 to 7.32.0 (#597) (1e7ca08)
  • upgrade eslint-config-standard from 16.0.2 to 16.0.3 (#589) (ec1c3de)
  • upgrade eslint-plugin-import from 2.22.1 to 2.23.4 (#584) (15a0b18)
  • upgrade tape from 5.2.0 to 5.2.2 (#588) (4139fd7)
  • upgrade webpack-cli from 4.5.0 to 4.7.2 (#586) (d588890)

6.2.0 (2021-07-07)

Features

  • initialize the state of a breaker on creation (#574) (b3dd431)

6.1.0 (2021-05-06)

Features

  • Add the ability to prime a breaker with previous stats (#568) (be26d74)

6.0.1 (2021-04-15)

Bug Fixes

  • return errors from invocation filtered errors (#567) (737e1b1), closes #556
  • docs: Fix documentation for default value of rollingPercentilesEnabled (#563) (93d5969)

6.0.0 (2021-03-18)

⚠ BREAKING CHANGES

A succesful erroFilter should not trigger the fallback function.

Previously, if an errorFilter function passed it would emit success but still call the fallback function. This corrects this behavior. even a passing errorFilter is a success

Bug Fixes

  • upgrade multiple dependencies with Snyk (#545) (9191afb)
  • upgrade multiple dependencies with Snyk (#548) (8db0e9e)
  • upgrade multiple dependencies with Snyk (#552) (7efcf91)
  • upgrade standard-version from 9.1.0 to 9.1.1 (#551) (16341bb)
  • upgrade tape from 5.1.1 to 5.2.0 (#553) (fa69c06)
  • upgrade webpack from 5.11.1 to 5.12.1 (#538) (34b6d61)
  • upgrade webpack from 5.12.1 to 5.20.1 (#543) (38b3e61)
  • upgrade webpack from 5.20.1 to 5.20.2 (#546) (d7952d5)
  • upgrade webpack from 5.20.2 to 5.22.0 (#549) (41efe20)
  • upgrade webpack-cli from 4.3.1 to 4.4.0 (#539) (b089f0b)
  • upgrade webpack-cli from 4.4.0 to 4.5.0 (#544) (83110a4)
  • fix!: A succesful erroFilter should not trigger the fallback function. (8a4fb7c), closes #540

5.1.3 (2021-01-25)

Bug Fixes

  • package.json & package-lock.json to reduce vulnerabilities (#533) (deaa258)
  • upgrade standard-version from 9.0.0 to 9.1.0 (#535) (3665bb0)
  • upgrade tape from 5.0.1 to 5.1.0 (#534) (be93012)
  • upgrade tape from 5.1.0 to 5.1.1 (#537) (78db7ba)
  • upgrade webpack from 5.10.3 to 5.11.0 (#529) (039fb48)
  • upgrade webpack from 5.11.0 to 5.11.1 (#532) (67d850e)
  • upgrade webpack-cli from 4.2.0 to 4.3.0 (#531) (9625ff7)
  • upgrade webpack-cli from 4.3.0 to 4.3.1 (#536) (afcc950)

5.1.2 (2021-01-07)

Bug Fixes

  • type-error on empty action (#528) (7b51dba), closes #524
  • upgrade @babel/core from 7.12.7 to 7.12.9 (#517) (2a28a73)
  • upgrade @babel/preset-env from 7.12.10 to 7.12.11 (#527) (bce3bfc)
  • upgrade babel-loader from 8.2.1 to 8.2.2 (#519) (654af20)
  • upgrade multiple dependencies with Snyk (#513) (7e3ef5c)
  • upgrade multiple dependencies with Snyk (#523) (480d2ff)
  • upgrade webpack from 5.10.1 to 5.10.3 (#526) (e72394c)
  • upgrade webpack from 5.4.0 to 5.6.0 (#512) (dc8f308)
  • upgrade webpack from 5.6.0 to 5.8.0 (#518) (f4438c8)
  • upgrade webpack from 5.8.0 to 5.9.0 (#520) (119ac47)
  • upgrade webpack from 5.9.0 to 5.10.1 (#525) (d552015)
  • using default parameter to avoid runtime error (#522) (6a6f08b)

5.1.1 (2020-12-07)

Bug Fixes

  • catch exceptions in fallback functions (#510) (34f75a2)
  • upgrade webpack from 5.3.2 to 5.4.0 (#507) (05a8876)
  • upgrade webpack-cli from 4.1.0 to 4.2.0 (#506) (ba91b77)

5.1.0 (2020-12-02)

Features

Bug Fixes

  • lint issues in test (#499) (35ddd8c)
  • package.json & package-lock.json to reduce vulnerabilities (#493) (03fed29)
  • upgrade @babel/core from 7.12.1 to 7.12.3 (#490) (6a73957)
  • upgrade babel-loader from 8.1.0 to 8.2.1 (#505) (885403b)
  • upgrade documentation from 13.0.2 to 13.1.0 (#491) (cc94100)
  • upgrade multiple dependencies with Snyk (#485) (efe299e)
  • upgrade multiple dependencies with Snyk (#487) (3afaa17)
  • upgrade webpack from 5.1.1 to 5.3.2 (#500) (1562a41)
  • upgrade webpack-cli from 4.0.0 to 4.1.0 (#501) (63d20c2)

Reverts

  • Revert "build: use pull_request_target in actions workflow (#476)" (3fa32b9), closes #476

5.0.2 (2020-10-14)

Bug Fixes

  • Adding docs about fallback parameters (#460) (e8989b6), closes #459
  • upgrade @babel/core from 7.11.0 to 7.11.1 (#458) (bd59b48)
  • upgrade @babel/core from 7.11.1 to 7.11.4 (#463) (2d4318d)
  • upgrade @babel/core from 7.11.5 to 7.11.6 (#467) (c0edb40)
  • upgrade multiple dependencies with Snyk (#466) (4dc36ef)
  • upgrade opener from 1.5.1 to 1.5.2 (#465) (96df963)
  • upgrade webpack from 4.44.1 to 4.44.2 (#471) (a9d8b86)

5.0.1 (2020-08-21)

Bug Fixes

  • [Snyk] Upgrade documentation from 12.1.4 to 12.2.0 (#411) (4ed0b30)
  • package.json to reduce vulnerabilities (#405) (186b464)
  • upgrade @babel/core from 7.10.4 to 7.10.5 (#449) (a18d669)
  • upgrade coveralls from 3.0.3 to 3.0.9 (#408) (d3bf2b4)
  • upgrade documentation from 12.0.0 to 12.1.4 (#407) (f2a2a67)
  • upgrade multiple dependencies with Snyk (#406) (c485c2d)
  • upgrade multiple dependencies with Snyk (#455) (1fb7791)
  • upgrade serve from 11.0.0 to 11.3.0 (#409) (8f35473)
  • upgrade standard-version from 8.0.1 to 8.0.2 (#448) (dcba522)
  • upgrade tape from 4.13.0 to 4.13.2 (#410) (b6bbf55)
  • upgrade webpack from 4.43.0 to 4.44.0 (#451) (ff127d5)
  • upgrade webpack from 4.44.0 to 4.44.1 (#456) (544fcd9)
  • test: Avoiding an UnhandledPromiseRejection (196457f)

5.0.0 (2020-02-20)

4.2.4 (2020-01-22)

Bug Fixes

4.2.3 (2020-01-03)

4.2.2 (2020-01-02)

4.2.1 (2019-11-08)

Bug Fixes

4.2.0 (2019-10-28)

Bug Fixes

  • clear intervals on shutdown (#378) (91e2dbe)
  • Clear reset timer on open() (#383) (7f488f1)
  • do not close if preexisting task resolves when state is not OPEN (#382) (7b92602)
  • circuit: remove unneeded resolve() (#377) (cde55eb)

Features

4.1.0 (2019-10-16)

Features

4.0.0 (2019-08-21)

Breaking Changes

  • The factory function has been removed in favor of simply using the CircuitBreaker constructor.
  • Prometheus and Hystrix metrics have been moved into their own repositories.
  • We no longer keep a set of all circuits

Features

  • refactor Prometheus and Hystrix metrics (#350) (3adbb90)

3.0.0 (2019-07-26)

src

BREAKING CHANGES

  • Remove the Promisify function from the CircuitBreaker factory

  • Node has its own built-in promisify function that can be used instead.

2.3.0 (2019-07-01)

Features

  • provide an Iterator of all active circuits (#344) (13616b0)

2.2.0 (2019-06-24)

Bug Fixes

Features

2.1.0 (2019-06-12)

Features

  • add function to get metrics for all circuits (#328) (ff29f2e)
  • Add original function parameters to the failure and timeout events (#326) (f8918c4), closes #324

2.0.0 (2019-06-05)

Build System

  • use node 12 on ci/cd in addition to 8 and 10 (93f8008)

Features

  • prometheus client integration (282b467)

Breaking Changes

  • health-check-failed and semaphore-locked events have been changed to healthCheckFailed and semaphoreLocked respectively

1.11.1 (2019-05-22)

Build System

  • don't fail coverage from untrusted forks (194e18d)
  • remove travis-ci now that circleci is good (9756bf5)
  • rename the workflow to test_node_versions in circleci (c7cc277)
  • set circleci to ignore gh-pages branch (23e1384)
  • set up coveralls (again); remove Makefile (d099b45)
  • switch to standardx for linting (4967736)
  • try circleci for continuous integration (1a77f3a)
  • try workflows for multiple version builds (5e9e6c8)
  • use codacy for coverage instead of coveralls (e359ab9)

Tests

  • generate browser/headless test suite (2d24b35)
  • improve circuit.shutdown() test (6841abc)
  • switch to serve instead of http-server for browser tests (50ccab7)

1.11.0 (2019-03-14)

Features

  • add errorFilter option to bypass incrementing failure stats (8018012)

1.10.1 (2019-02-25)

Bug Fixes

  • eliminates a bug where the circuit could remain halfOpen forever (0039ee1)

1.10.0 (2019-01-28)

Features

  • add circuit.shutdown() to shut a circuit down (e14796c)

1.9.0 (2018-10-27)

Features

  • add options.volumeThreshold (f9a720e)

1.8.0 (2018-10-02)

Bug Fixes

  • changed currentTime to number as specified in the docs (e816f43)

Features

  • add options.allowWarmUp as a creation option (#218) (ff42d1b)
  • change default capacity from 10 to MAX_SAFE_INTEGER (4a8b98b)

1.7.1 (2018-07-18)

1.7.0 (2018-06-06)

Bug Fixes

Features

1.6.0 (2018-05-24)

Features

  • pass error as parameter to fallback function (#197) (ae6c1cc)

1.5.0 (2018-04-25)

Bug Fixes

  • add full support for webpack and angular (#185) (a8cdad6)
  • address sec vuln in marked coming from jsdoc (224c6ef)
  • security issue related to electron version (#138) (4739c62)

Features

  • add enable/disable for a circuit (#160) (016eba5)
  • allow multiple circuits to aggregate stats (#140) (ba71840)

1.4.0 (2018-03-26)

Bug Fixes

  • address sec vuln in marked coming from jsdoc (224c6ef)
  • security issue related to electron version (#138) (4739c62)

Features

  • add enable/disable for a circuit (#160) (016eba5)
  • allow multiple circuits to aggregate stats (#140) (ba71840)

1.3.1 (2017-12-14)

Bug Fixes

  • build on windows10 due browserify limitations (#112) (dee4a9a)
  • halfOpen state does not reject and doesn't trigger a later re-try. (#120 (04df6f7)

1.3.0 (2017-10-16)

Bug Fixes

  • ensure breaker.fire() returns rejected promise when fallback fails (fbedb07)
  • ensure fallback event always fires (27c3f8b)
  • JSDoc now available for semaphore-locked event (6f6c9bd)

Features

  • Add health check function to a circuit breaker (#76) (0e39faa)

1.2.1 (2017-06-20)

1.2.0 (2017-06-20)

Features

1.1.0 (2017-06-06)

Bug Fixes

  • don't let circuits get stuck half open (5e1171c)
  • fix logic around pendingClose (4d89ae4)

Features

  • add ETIMEDOUT error code for timeout error (#64) (5df9f65)
  • addition of rolling percentile latency's. GH-ISSUE #38 (ce7b50d)
  • remove fidelity promises. (3f5827a)

1.0.0 (2017-04-06)

Bug Fixes

  • do not fire failure event on short circuit (ab87350)
  • make Status an EventEmitter (8aad11a)
  • remove default maxFailures option (be65d3b)

Features

  • add a group option. GH-Issue #43 (3052f23)
  • Add an example on how to use the Hystrix Metrics (fd8246a)
  • Addition of Hystrix Mertrics Stream. GH-ISSUE #39 (2d44df6)
  • circuit status now contains a rolling window (#34) (05c0a2f)
  • prefer an error percentage threshold (245d47b)

0.6.0 (2017-03-30)

Bug Fixes

  • circuit should emit failure event on fallback (f2594d8)
  • include the error when emitting the 'fallback event' (40eb2eb)
  • promise should reject when action throws (58dab98)
  • typo copy past duplicated property (54a27b9)

Features

  • add basic rolling stats to a circuit (8fb9561)
  • Add caching capability to circuits (6c3144f)
  • Add caching capability to circuits (0b717f6)
  • Applying code review (6a0f7ff)
  • Applying code review (8445a24)
  • circuits now have a name based on the action (f08d46e)

0.5.1 (2017-03-02)

0.5.0 (2016-12-22)

Bug Fixes

  • ensure fallback event emits after function call (df40ea7)
  • ensure pending close flag is reset (5a1b70b)
  • ensure that promise is rejected on fallback (d4496d8)
  • fix (again) browser load of circuitBreaker (58a80fb)
  • fix export of module in browser environment (5a0594c)

Features

  • allow for a CircuitBreaker as a fallback (85cbc34)
  • Full featured browser capabilities (2cc08f0)

0.4.0 (2016-12-20)

Features

  • Full featured browser capabilities (427c155)

0.3.0 (2016-12-16)

Features

  • create a browser distribution (cc8036c)

0.2.0 (2016-12-13)

Features

  • return 'this' from CircuitBreaker.fallback (159c006)

0.1.1 (2016-11-03)

Bug Fixes

  • Don't use Status for managing breaker state (8c4c659)
  • events: Include timeout in stats (abbdb61)

0.1.0 (2016-11-01)

Bug Fixes

  • Add 'use strict'; everywhere! (87ea863)
  • Add status for fallback calls. (fe1eeee)
  • Reset after resetTimeout when using fallbacks (47de312), closes #1

Features

  • events: Make CircuitBreaker an EventEmitter (dea7c53)
  • add methods to open and close the circuit manually (9c78ecf)
  • Handling for node-like callback functions (77f3d6b)
  • Make actions flexible (2672c34)