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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@nodelibraries/circuit-breaker

v1.0.2

Published

A lightweight wrapper around opossum for easier circuit breaker management

Readme

Circuit Breaker

@nodelibraries/circuit-breaker is a lightweight and powerful solution designed to protect your applications from unexpected failures. Built on top of the robust opossum circuit breaker library, it offers an intuitive API to seamlessly manage and control failure handling for your requests. Whether you're building a microservice architecture or managing complex network interactions, Circuit Breaker ensures your system remains resilient and fault-tolerant.

Features

  • 🛡️ Resilient by Default - Protect your applications from cascading failures
  • 🎯 Simple API - Easy to use with minimal configuration
  • 🔄 Multiple Levels - Support for endpoint, service, application, database, and external service levels
  • Event-Driven - Comprehensive event handling for monitoring and logging
  • 🎨 Framework Agnostic - Works with NestJS, Express, and any Node.js application
  • 📊 Statistics - Built-in statistics tracking for all circuit breakers
  • 🔧 Flexible Configuration - Customize timeout, error thresholds, and more
  • 🚀 TypeScript Support - Full TypeScript support with type safety
  • 📦 Lightweight - Minimal dependencies, built on top of opossum

Quick Start

npm install @nodelibraries/circuit-breaker
import {
  CircuitBreaker,
  CircuitBreakerLevel,
} from '@nodelibraries/circuit-breaker';
import axios from 'axios';

const circuitBreaker = new CircuitBreaker({
  timeout: () => console.error('Request timeout'),
  failure: () => console.error('Request failed'),
  open: () => console.error('Circuit breaker opened'),
});

async function fetchUserData(userId: number) {
  const response = await axios.get(`https://api.example.com/users/${userId}`);
  return response.data;
}

async function getUser(userId: number) {
  try {
    const user = await circuitBreaker.execute({
      level: CircuitBreakerLevel.External,
      name: 'fetchUserData',
      requestFn: fetchUserData,
      args: [userId],
      fallbackFn: () => ({ id: userId, name: 'Unknown User' }),
    });
    return user;
  } catch (error) {
    console.error('Failed to fetch user:', error);
    throw error;
  }
}

Documentation

📚 Full Documentation - Complete guide with examples and API reference

Installation

To install the library, run the following command:

npm install @nodelibraries/circuit-breaker

Usage

Importing the Library

import {
  CircuitBreaker,
  CircuitBreakerLevel,
} from '@nodelibraries/circuit-breaker';

nest.js example

import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
import axios from 'axios';
import {
  CircuitBreaker,
  CircuitBreakerLevel,
} from '@nodelibraries/circuit-breaker';

@Injectable()
export class AppService {
  private readonly circuitBreaker: CircuitBreaker;
  private readonly logger = new Logger(AppService.name);

  constructor() {
    this.circuitBreaker = new CircuitBreaker({
      timeout: () => {
        this.logger.error('Circuit Breaker is timeout');
      },
      failure: () => {
        this.logger.error('Circuit Breaker is failure');
      },
      reject: () => {
        this.logger.error('Circuit Breaker is reject');
      },
    });
  }

  private readonly stockServiceUrl = 'http://localhost:3001/stock';

  async checkStock(productId: number): Promise<{ available: boolean }> {
    const response = await axios.get(`${this.stockServiceUrl}/${productId}`);
    return response.data;
  }

  async checkStockFallbackFunction() {
    return { available: true };
  }

  async createOrder(productId: number) {
    try {
      const result: { available: boolean } = await this.circuitBreaker.execute({
        level: CircuitBreakerLevel.Endpoint,
        requestFn: this.checkStock.bind(this),
        // fallbackFn: this.checkStockFallbackFunction.bind(this),
        name: 'checkStock',
        args: [productId],
      });

      if (result?.available) {
        return { message: 'Order placed successfully!' };
      } else {
        throw new HttpException(
          'Product is out of stock',
          HttpStatus.BAD_REQUEST
        );
      }
    } catch (error) {
      throw new HttpException(
        'Service Unavailable',
        HttpStatus.SERVICE_UNAVAILABLE
      );
    }
  }
}

express.js example

import express from 'express';
import axios from 'axios';
import {
  CircuitBreaker,
  CircuitBreakerLevel,
} from '@nodelibraries/circuit-breaker';

const app = express();
const port = 3000;

const circuitBreaker = new CircuitBreaker({
  timeout: () => console.error('Circuit Breaker timeout'),
  failure: () => console.error('Circuit Breaker failure'),
  reject: () => console.error('Circuit Breaker reject'),
});

const stockServiceUrl = 'http://localhost:3001/stock';

async function checkStock(productId: number): Promise<{ available: boolean }> {
  const response = await axios.get(`${stockServiceUrl}/${productId}`);
  return response.data;
}

async function checkStockFallbackFunction() {
  return { available: true };
}

app.get('/create-order/:productId', async (req, res) => {
  const productId = parseInt(req.params.productId, 10);
  try {
    const result: { available: boolean } = await circuitBreaker.execute({
      level: CircuitBreakerLevel.Endpoint,
      requestFn: checkStock,
      fallbackFn: checkStockFallbackFunction,
      name: 'checkStock',
      args: [productId],
    });

    if (result?.available) {
      res.send({ message: 'Order placed successfully!' });
    } else {
      res.status(400).send({ message: 'Product is out of stock' });
    }
  } catch (error) {
    res.status(503).send({ message: 'Service Unavailable' });
  }
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

Fallback Function Example

You can provide a fallback function that will be called when the request fails. Below is an example of how to implement a fallback function:

async checkStockFallbackFunction(productId: number) {
  return { available: true }; // Default fallback value
}

async createOrder(productId: number) {
  try {
    const result: { available: boolean } = await this.circuitBreaker.execute({
      level: CircuitBreakerLevel.Endpoint,
      requestFn: this.checkStock.bind(this),
      fallbackFn: this.checkStockFallbackFunction.bind(this),
      name: 'checkStock',
      args: [productId],
      fallbackFnArgs: [productId], // Pass args to fallback function
    });

    if (result?.available) {
      return { message: 'Order placed successfully!' };
    } else {
      throw new HttpException('Product is out of stock', HttpStatus.BAD_REQUEST);
    }
  } catch (error) {
    throw new HttpException('Service Unavailable', HttpStatus.SERVICE_UNAVAILABLE);
  }
}

API

Circuit Breaker Levels

  • Endpoint: Circuit breaker for an individual endpoint.
  • Service: Circuit breaker for a specific service.
  • Application: Circuit breaker for the entire application.
  • Database: Circuit breaker for database calls.
  • External: Circuit breaker for external services.

Circuit Breaker Constructor

The CircuitBreaker class takes an optional eventHandlers object, which can be used to handle various circuit breaker events:

{
  fire?: () => void;
  reject?: () => void;
  timeout?: () => void;
  success?: () => void;
  failure?: () => void;
  open?: () => void;
  close?: () => void;
  halfOpen?: () => void;
  fallback?: () => void;
  semaphoreLocked?: () => void;
  healthCheckFailed?: () => void;
  shutdown?: () => void;
  cacheHit?: () => void;
  cacheMiss?: () => void;
}

Method: execute

The execute method runs the provided request function with circuit breaker protection:

async execute<T>(params: CircuitBreakerParams<T>): Promise<T>;

Parameters:

  • params: An object that contains:
    • level: (optional) The level of the circuit breaker
    • name: The name of the circuit breaker.
    • requestFn: The request function to be wrapped by the circuit breaker.
    • args: Arguments to be passed to the requestFn.
    • fallbackFn: (optional) fallback function to be executed in case of failure.
    • fallbackFnArgs: Arguments to be passed to the fallbackFnArgs.
    • options: (optional) custom circuit breaker options. If not provided the default values will be used.

Returns:

  • A promise that resolves to the result of the requestFn.

Example:

const result = await this.circuitBreaker.execute({
  level: CircuitBreakerLevel.Endpoint,
  requestFn: this.checkStock.bind(this),
  name: 'checkStock',
  args: [productId],
});

Options

The following options can be provided when creating a circuit breaker:

  • timeout: Max time (ms) for an operation to complete before failing. Default: 3000ms
  • errorThresholdPercentage: Failure rate (%) to trigger circuit breaker. Default: 50%
  • resetTimeout: Time (ms) before transitioning to "half-open" state. Default: 5000ms
  • rollingCountTimeout: Time window (ms) for tracking statistics. Default: 10000ms
  • rollingCountBuckets: Number of buckets in rollingCountTimeout window. Default: 10
  • name: Custom name for the circuit breaker. Default: 'CircuitBreaker'
  • rollingPercentilesEnabled: Enables percentile calculations. Default: false
  • capacity: Max concurrent requests. Default: 10
  • enabled: Enables circuit breaker on startup. Default: true
  • allowWarmUp: Prevents early circuit opening by ignoring failures initially. Default: false
  • volumeThreshold: Minimum requests before circuit breaker can open. Default: 5
  • errorFilter: Ignores specific errors if function returns true. Default: null
  • cache: Enables caching of first successful response. Default: false
  • cacheTTL: Cache expiration time (ms), 0 means never expires. Default: 0
  • cacheGetKey: Defines cache key. Default: null
  • cacheTransport: Custom caching mechanism with get, set, flush methods. Default: null
  • abortController: Uses AbortController to cancel async operations on timeout. Default: false
  • enableSnapshots: Enables snapshot events for statistics. Default: false
  • rotateBucketController: Shares EventEmitter for multiple circuit breakers. Default: null

Contributing

We welcome contributions of all kinds! To contribute, please check out the Contributing Guide.

Security Issues

If you find a security vulnerability, please refer to our Security Policies and Procedures.

Author

@nodelibraries/circuit-breaker is developed and maintained by Ferhat Yalçın.

License

MIT License