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

ts-easy-circuit-breaker

v1.3.0

Published

A lightweight and easy-to-use Circuit Breaker implementation in TypeScript.

Downloads

215

Readme

ts-easy-circuit-breaker

A lightweight and easy-to-use Circuit Breaker implementation in TypeScript.

Table of Contents

Installation

You can install the package using npm:

npm install ts-easy-circuit-breaker

Or using yarn:

yarn add ts-easy-circuit-breaker

Usage

Here's a basic example of how to use the Circuit Breaker:

import { CircuitBreaker } from "ts-easy-circuit-breaker";

const breaker = new CircuitBreaker({
  failureThreshold: 0.5,
  timeWindow: 10000,
  resetTimeout: 30000,
  minAttempts: 5,
  minFailures: 3,
});

async function makeHttpRequest() {
  // Your HTTP request logic here
}

try {
  const result = await breaker.execute(makeHttpRequest);
  console.log("Request successful:", result);
} catch (error) {
  if (error instanceof CircuitBreakerOpenError) {
    console.log("Circuit is open, request not made");
  } else {
    console.error("Request failed:", error);
  }
}

API

CircuitBreaker

The main class that implements the Circuit Breaker pattern.

Constructor

new CircuitBreaker(options: CircuitBreakerOptions)

Methods

  • execute<T>(fn: (...args: any[]) => Promise<T>, ...args: any[]): Promise<T> Executes the given function through the circuit breaker.

  • exportState(): CircuitBreakerState Returns the current state of the circuit breaker.

CircuitBreakerOpenError

An error class that is thrown when an execution is attempted while the circuit is open.

Configuration

The CircuitBreaker constructor accepts an options object with the following properties:

  • failureThreshold: The failure rate threshold above which the circuit should open. (0 to 1)
  • timeWindow: The time window in milliseconds over which the failure threshold is calculated.
  • resetTimeout: The time in milliseconds after which to attempt closing the circuit.
  • minAttempts: (Optional) The minimum number of attempts before the failure threshold is considered. Default is 5.
  • minFailures: (Optional) The minimum number of failures required to open the circuit, regardless of the failure rate. Default is 3.
  • minEvaluationTime: (Optional) The minimum time in milliseconds that must pass since the first failure before the circuit breaker starts evaluating whether to open. Default is 15ms.

Initial State and Serverless Environments

The CircuitBreaker constructor also accepts an optional initialState parameter, which is particularly useful in serverless environments where the state needs to be persisted externally (e.g., in Redis) between function invocations.

Here's an example of how to use the initialState:

import { CircuitBreaker, CircuitState } from "ts-easy-circuit-breaker";

// Assume this function retrieves the state from an external store (e.g., Redis)
async function getStateFromExternalStore() {
  // Implementation to fetch state from external store
}

// Assume this function saves the state to an external store
async function saveStateToExternalStore(state: CircuitBreakerState) {
  // Implementation to save state to external store
}

async function initializeCircuitBreaker() {
  const options = {
    failureThreshold: 0.5,
    timeWindow: 10000,
    resetTimeout: 30000,
    minAttempts: 5,
    minFailures: 3,
    minEvaluationTime: 5000,
  };

  const savedState = await getStateFromExternalStore();

  const circuitBreaker = new CircuitBreaker(options, savedState);

  // Optionally, you can listen for state changes and save the new state
  circuitBreaker.on("stateChanged", async (newState) => {
    await saveStateToExternalStore(newState);
  });

  return circuitBreaker;
}

// Usage in a serverless function
export async function handler(event, context) {
  const circuitBreaker = await initializeCircuitBreaker();

  try {
    const result = await circuitBreaker.execute(async () => {
      // Your protected operation here
    });
    return { statusCode: 200, body: JSON.stringify(result) };
  } catch (error) {
    if (error instanceof CircuitBreakerOpenError) {
      return { statusCode: 503, body: "Service temporarily unavailable" };
    }
    return { statusCode: 500, body: "Internal server error" };
  }
}

In this example, the Circuit Breaker's state is retrieved from an external store (like Redis) at the beginning of each serverless function invocation. This allows the Circuit Breaker to maintain its state across multiple invocations, which is crucial in serverless environments where the execution context is not preserved between invocations.

The initialState object should have the following structure:

interface CircuitBreakerState {
  state: CircuitState;
  failureCount: number;
  successCount: number;
  firstFailureTime: number;
  lastFailureTime: number;
  nextAttempt: number;
}

By using this approach, you can ensure that your Circuit Breaker behaves consistently in serverless environments, properly tracking failures and successes across multiple function invocations.

Events

The Circuit Breaker emits the following events:

  • 'openCircuit': Emitted when the circuit opens.
  • 'closeCircuit': Emitted when the circuit closes.
  • 'halfOpen': Emitted when the circuit transitions to the half-open state.
  • 'success': Emitted on successful execution.
  • 'failure': Emitted on failed execution.

You can listen to these events like this:

breaker.on("openCircuit", () => {
  console.log("Circuit opened");
});

Examples

HTTP Request Wrapper with Minimum Failures

import { CircuitBreaker } from "ts-easy-circuit-breaker";
import axios from "axios";

const breaker = new CircuitBreaker({
  failureThreshold: 0.5,
  timeWindow: 10000,
  resetTimeout: 30000,
  minAttempts: 10,
  minFailures: 5,
});

async function makeRequest(url: string) {
  return breaker.execute(async () => {
    const response = await axios.get(url);
    return response.data;
  });
}

// Usage
try {
  const data = await makeRequest("https://api.example.com/data");
  console.log(data);
} catch (error) {
  console.error("Request failed:", error);
}

In this example, the circuit will only open if there have been at least 5 failures, the failure rate is 50% or higher, and there have been at least 10 attempts within the 10-second time window.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License.