Skip to content

Latest commit

 

History

History
223 lines (165 loc) · 5.33 KB

README.md

File metadata and controls

223 lines (165 loc) · 5.33 KB

nice-retry

npm version Min zip size

A lightweight, zero-dependency retry utility that just works.

Quick Start

npm install nice-retry
import {retry} from 'nice-retry';

// Retry any async operation
await retry.async(() => someAsyncOperation());

// Retry fetch requests
await retry.fetch('https://api.example.com/data');

That's all you need for 90% of use cases! 🎉

Why nice-retry?

  • 🪶 Lightweight - Zero dependencies, tiny bundle size
  • 🔋 Batteries included - Built-in fetch support, backoff, jitter, fallbacks
  • 📦 Just works - Smart defaults, no complex configuration needed
  • 💪 TypeScript-first - Full type safety and autocompletion

Common Use Cases

// Retry with custom attempts
await retry.async(fn, {maxAttempts: 5});

// Retry with custom delay
await retry.async(fn, {initialDelay: 1000});

// Retry fetch with options
await retry.fetch('https://api.example.com/data', {
  retry: {maxAttempts: 3},
});

Advanced Features

🔄 Retry Conditions
await retry.async(fn, {
  retryIf: error => error.name === 'NetworkError',
});
🔙 Fallbacks
await retry.async(fn, {
  fallback: async () => backupOperation(),
  // Or multiple fallbacks
  fallback: [async () => primaryBackup(), async () => secondaryBackup()],
});
⏱️ Backoff Strategies

Backoff is a technique that progressively increases the delay between retry attempts. This helps prevent overwhelming the system being called and allows it time to recover from any issues. Like gradually stepping back when something's not working, rather than continuously trying at the same rate.

await retry.async(fn, {
  backoffStrategy: 'exponential', // 1s → 2s → 4s (default)
  backoffStrategy: 'linear', // 1s → 2s → 3s
  backoffStrategy: 'aggressive', // 1s → 3s → 9s
  backoffStrategy: 'fixed', // 1s → 1s → 1s
});
🎲 Jitter Strategies

Jitter adds randomness to retry delays to prevent multiple clients from retrying at exactly the same time. This is particularly important in distributed systems where synchronized retries could cause "thundering herd" problems - where many clients hit a service simultaneously after a failure.

await retry.async(fn, {
  jitterStrategy: 'full', // Random between 0 and delay (default)
  jitterStrategy: 'equal', // Random between delay/2 and delay*1.5
  jitterStrategy: 'decorrelated', // Independent random delays
  jitterStrategy: 'none', // Exact delays
});
🛑 Abort Control
const controller = new AbortController();

await retry.async(fn, {
  signal: controller.signal,
});

// Cancel retries
controller.abort();
📡 Fetch-Specific Options
await retry.fetch('https://api.example.com/data', {
  retry: {
    retryStatusCodes: [408, 429, 500, 502, 503, 504], // HTTP status codes that will trigger a retry
    retryNetworkErrors: true, // Whether to retry on network/connection errors
  },
});

Full API Reference

View Complete API

retry.async

function async<T>(
  fn: () => Promise<T>,
  options?: RetryAsyncOptions<T>,
): Promise<RetryAsyncResult<T>>;

interface RetryAsyncResult<T> {
  data: T; // The result of the function
  attempts: number; // The number of attempts made
  totalTime: number; // The total time taken for all attempts
  errors: Error[]; // The errors that occurred during the attempts
}

retry.fetch

function fetch(
  input: RequestInfo | URL,
  init?: RequestInit & {
    retry?: RetryFetchOptions;
  },
): Promise<RetryFetchResult>;

interface RetryFetchResult {
  response: Response; // The response from the fetch request
  attempts: number; // The number of attempts made
  totalTime: number; // The total time taken for all attempts
  errors: Error[]; // The errors that occurred during the attempts
}

Error Types

import {
  MaxRetriesExceededError, // Thrown when max retries are exceeded
  RetryAbortedError, // Thrown when the operation is aborted
  RetryConditionFailedError, // Thrown when the retry condition check fails
  RetryOperationError, // Base error for all retry operations
} from 'nice-retry';

TypeScript Support

Full TypeScript support with comprehensive type definitions:

import type {
  BackoffStrategy,
  JitterStrategy,
  RetryAsyncOptions,
  RetryFetchOptions,
} from 'nice-retry';

Default Configuration

All options are optional with smart defaults:

{
  maxAttempts: 3,
  initialDelay: 1000,
  maxDelay: 30000,
  jitterStrategy: 'full',
  backoffStrategy: 'exponential',
  retryNetworkErrors: true,
  retryStatusCodes: [408, 429, 500, 502, 503, 504]
}

Contributing

We welcome contributions! Check out our contributing guide.

License

MIT © Arshad Yaseen