Skip to content

ianfisk/Poli-C

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

59 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Poli-C

GitHub license npm version

Poli-C (pronounced "policy") is a fault tolerance utility for JavaScript. Inspired by Polly for .NET, this library's aim is to help applications handle transient failures in asynchronous actions.

Supported Policies

  • RetryPolicy - Sometimes you just need to try again.
  • CircuitBreakerPolicy - Don't kick services while they are down.

Installation

Using yarn:

yarn add poli-c

Or npm:

npm install --save poli-c

Then if using TypeScript or a module bundler such as webpack:

import Policy from 'poli-c'; // TypeScript
import { Policy } from 'poli-c'; // ES6

// or if not using ES6 modules
const { Policy } = require('poli-c');

RetryPolicy Examples

Basic

Retry forever

import { Policy } from 'poli-c';

...

const policy = Policy.waitAndRetryForever({ sleepDurationProvider: 1000 });

async function fetchThings() {
	const response = await fetch('https://servicethatmightfail.com/v1/things');
	const things = await response.json();
	return things;
}

...
const things = await policy.executeAsync(fetchThings);
...

Or not

const policy = Policy.waitAndRetry({ retryCount: 3, sleepDurationProvider: 1000 });

...
const things = await policy.executeAsync(fetchThings)
...

Additionally, control when the policy retries on error

const policy = Policy
	.handleError(error => error instanceof FetchError)
	.waitAndRetryForever({ sleepDurationProvider: 1000 });

async function fetchThings() {
	const response = await fetch('https://servicethatmightfail.com/v1/things');
	if (response.status !== 404 && !response.ok) {
		// if the request fails the policy will execute the action again
		throw new FetchError(response);
	}

	// but if parsing the JSON fails the action won't be retried
	const things = await response.json();
	return things;
}

...
const things = await policy.executeAsync(fetchThings);

With cancellation

The asynchronous function will be passed a cancellation token if one is provided to executeAsync. This allows for a cooperative cancellation approach (borrowed from the .NET framework). If canceled, executeAsync will currently return undefined.

import { Policy, CancellationTokenSource } from 'poli-c';

...

const policy = Policy.waitAndRetryForever({ sleepDurationProvider: 1000 });

async function fetchThings(cancellationToken) {
	const response = await cancelableFetch('https://servicethatmightfail.com/v1/things', cancellationToken);
	const things = await response.json();
	return things;
}

...

const cts = new CancellationTokenSource();
const promise = policy.executeAsync(fetchThings, cts.token);

// eventually cancel the execution
const timeout = setTimeout(() => {
	cts.cancel();
}, maxRequestTime);

const things = await promise;
if (!things) {
	// canceled
} else {
	// not canceled
	clearTimeout(timeout);
}
...

Until a valid result is obtained

import { Policy } from 'poli-c';

...

const policy = Policy
	.waitAndRetryForever({ sleepDurationProvider: 1000 })
	.untilValidResult(job => job.isComplete);

async function getJob(jobId) {
	const response = await fetch(`https://jobService.com/v1/jobs/${jobId}`);
	const job = await response.json();
	return job;
}

async function waitForJobCompletion(newJob, cancellationToken) {
	const completedJob = await policy.executeAsync(() => getJob(newJob.id), cancellationToken);
}

With exponential backoff

The library includes two backoff algorithms (full and equal jitter as described here) that are available for use.

import { Policy, backoffs } from 'poli-c';

...

const policy = Policy.waitAndRetry({ retryCount: 3, sleepDurationProvider: backoffs.fullJitter });

async function fetchThings() {
	const response = await fetch('https://servicethatmightfail.com/v1/things');
	const things = await response.json();
	return things;
}

...
const things = await policy.executeAsync(fetchThings);
...

Additionally, a custom backoff algorithm can be used:

const policy = Policy.waitAndRetry({ retryCount: 3, sleepDurationProvider: ({ retryAttempt }) => 1000 * retryAttempt });

CircuitBreakerPolicy Examples

Basic

import { Policy } from 'poli-c'; // ES6

const policy = Policy
	.handleError(error => error instanceof FetchError)
	.circuitBreaker({
		samplingDurationMs: 5000,
		failureThreshold: 0.75,
		minimumThroughput: 4,
		breakDurationMs: 5000,
	});

async function fetchThings() {
	const response = await fetch('https://servicethatmightfail.com/v1/things');
	if (response.status !== 404 && !response.ok) {
		throw new FetchError(response);
	}

	const things = await response.json();
	return things;
}

...

try {
	const things = await policy.executeAsync(fetchThings);
	return things;
} catch (e) {
	// this error may have been thrown immediately by circuit breaker if the
	// failure threshold has been met in the sampling period
	log(e);
}

Need more information about different policies and their APIs? See the API Reference!

About

A fault tolerance utility for JavaScript.

Resources

License

Stars

Watchers

Forks

Packages

No packages published