Building a Circuit Breaker in Node.js (Part 2)
Tags: webdev, node, javascript, api
Published: 2020-02-25 16:39:50

Welcome to Part 2 in our series on building your own circuit breaker in Node.js. In Part 1, [Building a Circuit Breaker in Node.js](https://bearer.sh/blog/build-a-circuit-breaker-in-node-js), we built a starter version that handles the core [states of a circuit breaker](https://www.bearer.sh/blog/circuit-breaker-design-pattern). In this article, we will add configurability, manual overrides, and fallback request support. You can find the complete code for each example [here](https://gist.github.com/markmichon/82f8176a47780a0e168918ded25e7bf9).

## Make it configurable

In part 1, we put all the thresholds and timeouts directly into the breaker. It would be better to make each instance of the circuit breaker configurable. Our result will look like this:

```javascript
const options = {
  failureThreshold: 3,
  successThreshold: 2,
  timeout: 6000
}

const breaker = new CircuitBreaker(request, options)
```

To make this happen we need to adjust our constructor in `CircuitBreaker`.

```javascript
class CircuitBreaker {
  /* 1 */
  constructor(request, options = {}) {
    /* 2 */
    const defaults = {
      failureThreshold: 3,
      successThreshold: 2,
      timeout: 6000
    }
    Object.assign(this, defaults, options, {
      /* 3 */
      request: request,
      state: "CLOSED",
      failureCount: 0,
      successCount: 0,
      nextAttempt: Date.now()
    })
  }

  //...
}
```

Above _(1)_, the constructor now takes an `options` argument in addition to the request. Next, we declare some defaults _(2)_ for the user-configurable properties. `Object.assign` is then used to add the defaults, the user options, and our _internal_ properties _(3)_ plus the request to `this`. Why all the mixing of objects? We want to make sure users cannot override our internal properties. The result is a version of `CircuitBreaker` that behaves like our original, but now accepts options for `failureThreshold`, `successThreshold`, and `timeout` on instantiation.

_Note: You could also use class private properties instead of the method above, but support is still a bit new or spotty._

The configurable code of our circuit breaker can be found [here](https://gist.github.com/markmichon/82f8176a47780a0e168918ded25e7bf9#file-circuitbreaker-configurable-js).

## Add manual state overrides

Sometimes it can be useful to offer manual overrides for your circuit breaker. Maybe you're dealing with a finicky API that occasionally needs to be retried out of the flow of the circuit. Perhaps new information comes in from a related source–like a [webhook](https://www.bearer.sh/blog/consuming-webhooks-with-node-js-and-express)–that makes you want to "break out" of the current state.

To do this, we will add helper methods to our `CircuitBreaker` class that swap the state, and reset any properties that affect the logic.

```javascript
class CircuitBreaker {
  //...
  open() {
    this.state = "OPEN"
    this.nextAttempt = Date.now() + this.timeout
  }

  close() {
    this.successCount = 0
    this.failureCount = 0
    this.state = "CLOSED"
  }

  half() {
    this.state = "HALF"
  }

  //...
}
```

You can replace some portions of `fail` and `success` with these new helpers to reduce some repetition. More importantly, they now give us access to `breaker.open()`, `breaker.close()`, and `breaker.half()` in our instances of the circuit breaker. This way your app can have influence over the state from the outside.

The code with manual overrides for the circuit breaker can be found [here](https://gist.github.com/markmichon/82f8176a47780a0e168918ded25e7bf9#file-circuitbreaker-manual-overrides-js).

## Fallback functionality

Imagine an API you use or perhaps a regional resource (AWS East vs West) is having problems. You'd like your code to adapt and call an alternate resource. We talk about the power of switching to a fallback in [Consuming Webhooks with Node.js and Express](https://www.bearer.sh/blog/consuming-webhooks-with-node-js-and-express).

Let's add a fallback to `CircuitBreaker`. First, we will create a new test request. In part 1 we had `unstableRequest` in our `test.js` file. This is still our main resource, but let's create an additional function to call if a problem happens with our main resource.

```javascript
function expensiveResource() {
  return new Promise((resolve, reject) => {
    resolve({ data: "Expensive Fallback Successful" })
  })
}
```

This request is reliable, but more costly than our `unstableRequest`. While we're in `test.js`, make a change to the instantiation of `breaker`:

```javascript
const breaker = new CircuitBreaker(unstableRequest, expensiveResource)

// Alternately, if you set up the configurability from earlier
const breaker = new CircuitBreaker(unstableRequest, {
  fallback: expensiveResource,
  failureThreshold: 2
  // ...etc
})
```

Now move back to `CircuitBreaker.js`. The first thing we need to do is accept the new argument (or property on the options object).

```javascript
// Version 1. If using the code without configuration (from Part 1)
class CircuitBreaker {
  constructor(request, fallback = null) {
    /* ... */
  }
  /* ... */
}

// Version 2. If using a configurable "options" argument
class CircuitBrekaer {
  constructor(request, options) {
    const defaults = {
      failureThreshold: 3,
      successThreshold: 2,
      timeout: 6000,
      fallback: null
    }
    Object.assign(this, defaults, options, {
      /* ... */
    })
  }
  /* ... */
}
```

This adds the fallback request just like any other argument. To help with our logic later, we also set it's default value to `null` in case it isn't set by the user.

Next, we'll create a method on `CircuitBreaker` to attempt the fallback request.

```javascript
class CircuitBreaker {
  /* ... */
  async tryFallback() {
    // Attempting fallback request
    try {
      const response = await this.fallback()
      return response
    } catch (err) {
      return err
    }
  }
}
```

We will use this method when the original request fails. It won't affect the circuit breaker itself, since the original resource is still having problems. That is why we won't run the fallback response through the `success` or `fail` flows. Let's call `tryFallback` when a request fails.

```javascript
  fail(err) {
    this.failureCount++
    if (this.failureCount >= this.failureThreshold) {
      this.state = "OPEN"
      this.nextAttempt = Date.now() + this.timeout
    }
    this.status("Failure")
    if (this.fallback) return this.tryFallback() /* 1 */
    return err
  }
```

Everything above is the same as our original code, with the exception of the line at **1**. It checks if `this.fallback` has been set, and if so it will return our newly created `tryFallback` method.

The use of `return` in these code blocks is important. It allows us to pass the result back up to the original function that started the request.

The full code for the circuit breaker with fallback functionality can be found [here](https://gist.github.com/markmichon/82f8176a47780a0e168918ded25e7bf9#file-circuitbreaker-with-fallback-js).

## Resilient and ready for anything

With everything in place, you now have the foundation to put together a strategy that resilient code patterns to manage the unreliability of the third-party APIs or resources your applications rely on.

While we've gone through the foundations in Part 1, and some advanced features in this article, building your own can still be challenging. Depending on the application you're building and the stack you're working in, using an off the shelf circuit breaker like [opossum for Node.js](https://github.com/nodeshift/opossum), [circuit_breaker for Ruby](https://github.com/wsargent/circuit_breaker), [go-circuitbreaker for Go](https://github.com/mercari/go-circuitbreaker), or [circuitbreaker for python](https://pypi.org/project/circuitbreaker/) might be a good choice.

At Bearer we're building a product that handles much of the work required to shield your app from third-party API failures and make it more resilient. This includes features like retries on specific response types, and much more to come in the future. Have a look, and get started using [Bearer](https://bearer.sh) today.

Like this article and want to see more? Connect with us [@BearerSH](https://twitter.com/bearersh) and check [The Bearer Blog](https://bearer.sh/blog) for more articles like this from the team at Bearer.

📢 _[Building a Circuit Breaker in Node.js (Part 2)](https://blog.bearer.sh/build-a-circuit-breaker-in-node-js-part-2/) was originally published on [The Bearer blog](https://blog.bearer.sh)._