0.0.0 • Published 12 months ago

@da440dil/cbr v0.0.0

Weekly downloads
-
License
MIT
Repository
-
Last release
12 months ago

@da440dil/cbr

GitHub Actions Coverage Status

Circuit breaker.

Example decorator (typescript version >= 5):

import { promisify } from 'util';
import http from 'http';
import { CircuitBreaker } from '@da440dil/cbr';

// Create the circuit breaker which switches from "Closed" to "Open" state on first error,
// from "Open" to "HalfOpen" state after 100ms, from "HalfOpen" to "Closed" state on first success.
const breaker = new CircuitBreaker({ errorThreshold: 1, resetTimeout: 100, successThreshold: 1 });

class Client {
	private url = 'http://localhost:3000';
	// Decorate the class method with circuit breaker logic.
	@CircuitBreaker.Breakable(breaker)
	public get(): Promise<string> {
		return new Promise((resolve, reject) => {
			const req = http.get(this.url, (res) => {
				if (res.statusCode !== 200) {
					res.resume();
					return reject(new Error(`Failed with statusCode ${String(res.statusCode)}`));
				}
				let data = '';
				res.on('data', (chunk) => { data += chunk; });
				res.on('end', () => { resolve(data); });
			});
			req.on('error', reject);
		});
	}
}
const client = new Client();
const get = async () => {
	try {
		const data = await client.get();
		console.log(`DATA: ${data}`);
	} catch (err) {
		console.log(err instanceof Error ? `ERROR: ${(err).message}` : err);
	}
};

let x = 0;
const server = http.createServer((_, res) => {
	const statusCode = x > 2 || x % 2 ? 418 : 200; // { 0 => 200, 1 => 418, 2 => 200, ... => 418 }
	res.writeHead(statusCode).end(`{ x: ${x} }`);
	x++;
});
server.listen(3000);

async function main() {
	for (let i = 0; i < 3; i++) {
		await get();
	}
	await promisify(setTimeout)(100);
	await get();
	// Output:
	// DATA: { x: 0 }
	// ERROR: Failed with statusCode 418
	// ERROR: Circuit broken
	// DATA: { x: 2 }
}

main().then(() => { process.exit(0); }).catch((err) => { console.error(err); process.exit(1); });
npm run file examples/decorator.ts

Example function:

import { promisify } from 'util';
import http from 'http';
import { CircuitBreaker } from '@da440dil/cbr';

class Client {
	// Create the circuit breaker which switches from "Closed" to "Open" state on first error,
	// from "Open" to "HalfOpen" state after 100ms, from "HalfOpen" to "Closed" state on first success.
	private breaker = new CircuitBreaker({ errorThreshold: 1, resetTimeout: 100, successThreshold: 1 });
	private url = 'http://localhost:3000';
	public get(): Promise<string> {
		// Execute the function with circuit breaker logic.
		return this.breaker.exec(() => {
			return new Promise((resolve, reject) => {
				const req = http.get(this.url, (res) => {
					if (res.statusCode !== 200) {
						res.resume();
						return reject(new Error(`Failed with statusCode ${String(res.statusCode)}`));
					}
					let data = '';
					res.on('data', (chunk) => { data += chunk; });
					res.on('end', () => { resolve(data); });
				});
				req.on('error', reject);
			});
		});
	}
}
const client = new Client();
const get = async () => {
	try {
		const data = await client.get();
		console.log(`DATA: ${data}`);
	} catch (err) {
		console.log(err instanceof Error ? `ERROR: ${(err).message}` : err);
	}
};

let x = 0;
const server = http.createServer((_, res) => {
	const statusCode = x > 2 || x % 2 ? 418 : 200; // { 0 => 200, 1 => 418, 2 => 200, ... => 418 }
	res.writeHead(statusCode).end(`{ x: ${x} }`);
	x++;
});
server.listen(3000);

async function main() {
	for (let i = 0; i < 3; i++) {
		await get();
	}
	await promisify(setTimeout)(100);
	await get();
	// Output:
	// DATA: { x: 0 }
	// ERROR: Failed with statusCode 418
	// ERROR: Circuit broken
	// DATA: { x: 2 }
}

main().then(() => { process.exit(0); }).catch((err) => { console.error(err); process.exit(1); });
npm run file examples/function.ts