easy-circuit-breaker v1.0.2
Easy Circuit Breaker
easy-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, Easy Circuit Breaker ensures your system remains resilient and fault-tolerant.
Installation
To install the library, run the following command:
npm install easy-circuit-breaker
Usage
Importing the Library
import { CircuitBreaker, CircuitBreakerLevel } from 'easy-circuit-breaker';
nest.js example
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
import axios from 'axios';
import { CircuitBreaker, CircuitBreakerLevel } from 'easy-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 'easy-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 breakername
: The name of the circuit breaker.requestFn
: The request function to be wrapped by the circuit breaker.args
: Arguments to be passed to therequestFn
.fallbackFn
: (optional) fallback function to be executed in case of failure.fallbackFnArgs
: Arguments to be passed to thefallbackFnArgs
.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: 3000mserrorThresholdPercentage
: Failure rate (%) to trigger circuit breaker. Default: 50%resetTimeout
: Time (ms) before transitioning to "half-open" state. Default: 5000msrollingCountTimeout
: Time window (ms) for tracking statistics. Default: 10000msrollingCountBuckets
: Number of buckets inrollingCountTimeout
window. Default: 10name
: Custom name for the circuit breaker. Default: 'CircuitBreaker'rollingPercentilesEnabled
: Enables percentile calculations. Default: falsecapacity
: Max concurrent requests. Default: 10enabled
: Enables circuit breaker on startup. Default: trueallowWarmUp
: Prevents early circuit opening by ignoring failures initially. Default: falsevolumeThreshold
: Minimum requests before circuit breaker can open. Default: 5errorFilter
: Ignores specific errors if function returns true. Default: nullcache
: Enables caching of first successful response. Default: falsecacheTTL
: Cache expiration time (ms), 0 means never expires. Default: 0cacheGetKey
: Defines cache key. Default: nullcacheTransport
: Custom caching mechanism withget
,set
,flush
methods. Default: nullabortController
: UsesAbortController
to cancel async operations on timeout. Default: falseenableSnapshots
: Enables snapshot events for statistics. Default: falserotateBucketController
: SharesEventEmitter
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
easy-circuit-breaker is developed and maintained by Ferhat Yalçın.