npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

promise-circuitbreaker

v1.0.11

Published

A circuit breaker implementation

Downloads

219

Readme

Build Status

Install

You can install locally with npm install promise-circuitbreaker.

Introduction

A circuit breaker implementation for node with three main features:

  • It wraps "node functions" and uses bluebird Promise library to "promisify" the response as default (you can choose to use the native implementation).
  • It uses a rolling window to calculate the circuit's health.
  • It can use different error thresholds for different error types.

For more information about the Circuit Breaker pattern you can read Martin Fowler's CircuitBreaker.

The rolling window is based on Netflix's Hystrix, as is the half-open state in which a test request will be made to close the circuit on success.

The package provides two main classes, the CircuitBreaker, and the RequestCircuitBreaker which wraps the request module.

Quick Start

var mysql = require('mysql'),
    CircuitBreaker = require('promise-circuitbreaker'),
    TimeoutError = CircuitBreaker.TimeoutError,
    OpenCircuitError = CircuitBreaker.OpenCircuitError;

var pool = mysql.createPool({
    host: 'localhost',
    database: 'test'
});

var cb = new CircuitBreaker(pool.query, pool, {
    timeout: 1000,
    errorThreshold: 0.1
});

// Using bluebird catch syntax
cb.exec('SELECT sleep(0.1)').spread(function(rows, fields) {
    console.log("OK!", rows);
}).catch(TimeoutError, function(error) {
    console.log("Handle timeout here");
}).catch(OpenCircuitError, function(error) {
    console.log("Handle open circuit error here");
}).catch(function(error) {
    console.log("Handle any error here");
}).finally(function() {
    cb.stopEvents();
    pool.end();
});

Request Circuit Breaker Quick Start

var CircuitBreaker = require('promise-circuitbreaker'),
    RequestCircuitBreaker = CircuitBreaker.RequestCircuitBreaker,
    TimeoutError = CircuitBreaker.TimeoutError,
    OpenCircuitError = CircuitBreaker.OpenCircuitError;

var isError = function(error, response, body) {
    if (error) return error;
    if (response.statusCode == 503) {
        var unavailableError = new Error();
        unavailableError.name = "ServiceUnavailableError";
        return unavailableError;
    }
    return null;
};

var cb = new RequestCircuitBreaker({
    isErrorHandler: isError,
    errorThreshold: 0.1, // allow 10% error rate
    errorNamesThresholds: {
        ServiceUnavailableError: 0 // but close circuit on first unavailable error
    }
});

cb.exec({url: 'https://graph.facebook.com/19292868552', json: true})
.spread(function(response, page) {
    console.log(page);
}).catch(TimeoutError, function(error) {
    console.log("Timeout!", error);
}).catch(OpenCircuitError, function(error) {
    console.log("Circuit is open!");
}).catch(function(error) {
    console.log("Other error");
}).finally(function() {
    cb.stopEvents();
});

Health Window

The circuit breaker monitors the health using a rolling window. The total period of time is determined by the number of windows and the size of each window. This is the same as the "buckets" in Netflix's Circuit Breaker The defaults are the same as in Netflix's implementation (10 intervals of 1 second each).

Concurrency

The circuit breaker keeps a count of the current "active" calls. These are calls which have begun but whose callback has not yet been called and which have not yet timedout. Disabled by default, you can configure the circuit breaker to queue requests once the active counter reaches a certain level. This might help you protect your backend by limiting the simultaneous calls made to it. There are, however, some things to keep in mind.

First of all, the wrapped resource might have it's own control. This is the case if you are using a mysql pool of connections, for example. The request module uses pooling which defaults to node's global http.agent.maxSockets. So if you are using the RequestCircuitBreaker, even if you do not restrict the concurrency at the circuit breaker's level, you might notice that there are never more than 5 active connections (per host) which is node's default.

You might want to use the circuit breaker's concurrency throttling to alter this behaviour. Consider a RESTful API, you could set node's (or the request module) pooling to 100 but have different circuit breakers with different concurrency settings for different resources.

However, please notice that the current implementation does not care how much time a call remains in the queue. The timeout control starts once the call is actually executed. So, the end-user could end waiting a more than expected even if the call succeeds very quickly, because it might have spent some time in the queue.

Example App

If you download the project you can run a more complete example. For more information please read its readme.

Configuration

There are several parameters which allow you to configure the circuit breaker's behaviour, allowing you to adjust it to your particular needs. Please look at the docs for more details.

Volume Threshold

The minimum amount of total calls in the health window required to start calculating the circuit's health. The circuit remains closed until this level is reached. You can set it to zero to always calculate the circuit's health. With a positive errorThreshold, this means that if the first request is an error, the circuit will trip.

Timeout

The maximum amount of time the circuit breaker waits for the callback before failing with a TimeoutError. You can set it to zero to disable this functionality. The circuit breaker will only trip on errors.

Error Threshold

The ratio of errors in the current health window which trips (opens) the circuit. The value is expressed as a float between 0 and 1. Setting it two 0 trips the circuit on the first error. Setting it to one, forces the circuit to always remain closed. You can also set a lower error rate for particular errors.

Running the tests

You can run the tests with make test. The main test is written with yadda and run through mocha.

You can use the spec reporter to see the test details:

make test REPORTER=spec GREP='--grep "New circuit should be closed"'


  Circuit Breaker
    ✓ New circuit should be closed


  1 passing (22ms)

License

The MIT License (MIT)

Copyright (c) 2014 Pablo de León Belloc

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.