top of page

SNIPPETS LTD.

Circuit Breaker with Opossum in NestJS

  • Writer: Pavol Megela
    Pavol Megela
  • Nov 14, 2024
  • 4 min read

In modern applications, we often rely on external services, APIs, or databases. When these dependencies fail our entire system suffer. This is where the Circuit Breaker pattern comes into a play.


A Circuit Breaker acts as a safeguard, stopping repeated calls to failing services and allowing them time to recover. This prevents cascading failures and improves system stability.


We look at the simple implementation of a Circuit Breaker in NestJS using Opossum library. We break down the key concepts and show how to integrate it into a real-world NestJS service.


Understanding circuit breakers

Circuit Breaker is a simple concept. It monitors calls to an external service and if failures happen too often, it temporarily blocks further requests. This prevents your system from getting stuck waiting for a service that’s down, instead it saves the work for later and once the service is available again, it will execute it.


Circuit breakers have three states:

  • Closed - Everything is working fine. Requests flow normally

  • Open - Too many failures happened, so the circuit "breaks" blocking requests for a while

  • Half-Open – After a timeout it allows a few test requests. If they succeed, the circuit closes. If they fail, it stays open


Think of it like an automatic switch that stops sending requests to a broken service and tries again later. This protects your app from unnecessary slowdowns and crashes.

Next we take a look on how to set up a Circuit breaker in NestJS project with Opossum.


Installing and configuring Opossum

Let’s install Opossum a circuit breaker library for Node.js. You can read more about it here npmjs/opossum.

npm install opossum

Once installed we can use it to wrap an API call or any external dependency to prevent failures from affecting our app. Next, we’ll implement it inside a NestJS service.


Basic configurations

Opossum provides several configuration options to control how the circuit breaker behaves. Here are the most important ones

  • timeout - Maximum time (in milliseconds) a request can take before it's considered failed

  • errorThresholdPercentage - The failure percentage that triggers the circuit to open (50 means if 50% of requests fail -> the circuit opens)

  • resetTimeout - How long (in milliseconds) the circuit stays open before trying again in the half-open state


Now let's look at the coding part

import * as CircuitBreaker from 'opossum';

const options = {
  timeout: 3 * 1000,
  errorThresholdPercentage: 50,
  resetTimeout: 5 * 1000,
};

const breaker = new CircuitBreaker(yourFunction, options);

Implementing a Circuit Breaker

To implement the circuit breaker, we need to do the following:

  1. Create an instance of Opossum

  2. Configure the circuit breaker

  3. Wrap the API call inside the circuit breaker - This is the execution we want to monitor for failures

  4. Set a fallback function - This defines what should happen if the external service is unavailable (logging the failure, triggering alternative flows, or saving the event for later processing)


Here’s how the coding part looks

@Injectable()
export class ExternalService {
  private breaker: CircuitBreaker;

  public constructor(private readonly httpService: HttpService) {
    const options = {
      timeout: 3 * 1000,
      errorThresholdPercentage: 50,
      resetTimeout: 5 * 1000,
    };

    this.breaker = new CircuitBreaker(this.fetchData.bind(this), options);

    this.breaker.fallback(() => {
      // Here you will:
      // Log the failure
      // Trigger alternative flow
      // Save failed event for later processing
    });
  }

  public async getData() {
    return this.breaker.fire();
  }

  private async fetchData(): Promise<ExampleResponse> {
    return this.httpService.get('https://api.example.com/data').toPromise();
  }
}

How it works:

  • The circuit breaker wraps fetchData() and defines failure callback

  • getData() gets called instead of fetchData(). This ensures that all requests pass through the circuit breaker logic.

  • fetchData() is being called by getData() and it makes an API request

  • If failures exceed the threshold requests are blocked for a while

  • The fallback function is triggered when the circuit is open, ensuring that failures are logged or saved for later processing instead of just returning a static response.


This ensures that if the external service is unavailable, the application won't keep making failing requests. Instead, it waits before retrying, improving system resilience.


Circuit Breaker Events in Opossum

Opossum provides event listeners that allow us to track the circuit breaker’s state and respond accordingly. These events help with monitoring, logging, and triggering alternative actions when failures occur.


Here are the key events you can listen for


  1. open - Circuit Breaker Opened

Triggered when the failure threshold is reached, and the circuit moves to the open state (blocking further requests).

this.breaker.on('open', () => {
  console.warn('Circuit breaker opened! External service is failing.');
});

  1. close - Circuit Breaker Closed

Triggered when the circuit recovers and moves back to the closed state (allowing requests again).

Use Case: If you’ve stored failed requests (for example in Outbox Table), this is the time to reprocess them.

this.breaker.on('close', () => {
  console.log('Circuit breaker closed. Service is healthy again.');
  // Trigger reprocessing of failed requests
});

  1. halfOpen - Circuit Breaker Half-Open

After the circuit opens, a timeout starts as per options.resetTimeout. Once this period ends, opossum enters the halfOpen state. The next circuit activation will execute the action again. Success closes the circuit and triggers the close event; failure or timeout returns it to the open state.

this.breaker.on('halfOpen', () => {
  console.log('Circuit breaker is half-open. Testing service availability...');
});

Best practices

When using a circuit breaker it’s important to follow best practices to ensure reliability. Here are key considerations:


  1. Choose the right timeout

    1. Set a reasonable timeout value based on your expected API response time

    2. Too short -> Unnecessary failures

    3. Too long -> Wasted time waiting for slow responses

  2. Tune failure threshold and reset timeout There's no one-size-fits-all, you need to observe your system and learn how it works. See what settings works best for you.

    1. errorThresholdPercentage should match the acceptable failure rate of your system

    2. resetTimeout should allow enough time for recovery before retrying

  3. Use fallbacks wisely

    A fallback function should not just return a default response but also:

    1. Log the failure

    2. Save the request for later processing, store them in an Outbox Table or a queue for later retry

    3. Notify monitoring systems

  4. Avoid overuse

    1. Not every API call needs a circuit breaker

    2. Use it for critical external services, not every database or microservice call

  5. Test failure scenarios

    1. Simulate failures (timeouts, API downtime) to ensure the circuit breaker behaves as expected

    2. Ensure fallbacks and logging work properly


That's all for now

Circuit breakers are essential for building resilient applications, preventing cascading failures, and handling unreliable external services. By integrating Opossum with NestJS, we can protect our APIs from slow or failing dependencies while ensuring system stability. Now go ahead and implement it in your project.

コメント


bottom of page