/js-re

Abstraction for retry strategies

Primary LanguageTypeScriptMIT LicenseMIT

@da440dil/re

GitHub Actions Coverage Status

Abstraction for retry strategies.

Example decorator (typescript version >= 5):

import http from 'http';
import { Re } from '@da440dil/re';

// Create retry strategy which retries execution in case of an error after 10ms, 20ms, 30ms.
const re = new Re([10, 20, 30]);

class Client {
	private url = 'http://localhost:3000';
	// Decorate the class method with retry logic.
	@Re.Tryable(re)
	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();
	}
	// Output:
	// 	DATA: { x: 0 }
	// DATA: { x: 2 }
	// ERROR: Failed with statusCode 418
}

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

Example function:

import http from 'http';
import { Re } from '@da440dil/re';

class Client {
	// Create retry strategy which retries execution in case of an error after 10ms, 20ms, 30ms.
	private re = new Re([10, 20, 30]);
	private url = 'http://localhost:3000';
	public get(): Promise<string> {
		// Execute the function with retry logic.
		return this.re.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();
	}
	// Output:
	// 	DATA: { x: 0 }
	// DATA: { x: 2 }
	// ERROR: Failed with statusCode 418
}

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