Skip to content

🦜 Type-safe, lightweight retry utility for async operations that simply works.

License

Notifications You must be signed in to change notification settings

arshad-yaseen/nice-retry

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

36 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

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

About

🦜 Type-safe, lightweight retry utility for async operations that simply works.

Resources

License

Code of conduct

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published