Skip to content

timursevimli/tekrar

Repository files navigation

Tekrar

ci Status snyk npm downloads/month npm downloads license

An abstraction for handling retry strategies, including exponential backoff and custom configurations, for operations that fail.

Note: "Tekrar" means "repeat" or "retry" in Turkish, reflecting the module's purpose.

Features

  • Simple and lightweight retry mechanism
  • Support for both synchronous and asynchronous functions
  • Configurable retry count and delay
  • Timeout support to limit maximum running time
  • Custom error handling and recovery functions
  • TypeScript support

Installation

npm install tekrar

Usage

Basic Usage

const tekrar = require('tekrar');

// Wrap a function that might fail
const fetchData = tekrar(
  async () => {
    const response = await fetch('https://api.example.com/data');
    if (!response.ok) throw new Error('API request failed');
    return response.json();
  },
  { count: 3, delay: 1000 },
);

// Use the wrapped function
try {
  const data = await fetchData();
  console.log('Data:', data);
} catch (error) {
  console.error('All retries failed:', error);
}

With Recovery Function

const tekrar = require('tekrar');

const sendEmail = tekrar(
  async (recipient, content) => {
    // Email sending logic that might fail
    return emailService.send(recipient, content);
  },
  {
    count: 3,
    delay: 2000,
    recovery: async (recipient, content) => {
      // Log the failure or perform alternative action
      console.log(`Failed to send email to ${recipient}, retrying...`);
      // You could also modify the content or recipient before the next retry
    },
    onError: (error) => {
      // Log each error
      console.error('Email sending error:', error.message);
    },
  },
);

// Use the wrapped function
try {
  await sendEmail('user@example.com', 'Hello, world!');
  console.log('Email sent successfully');
} catch (error) {
  console.error('Failed to send email after multiple attempts');
}

API

tekrar(task, options)

Creates a wrapped function that will retry the given task according to the specified options.

Parameters

  • task (Function): The function to retry. Can be synchronous or asynchronous.
  • options (Object, optional): Configuration options for retry behavior.
    • count (Number, default: 1): Maximum number of retry attempts.
    • delay (Number, default: 0): Delay in milliseconds between retry attempts.
    • timeout (Number, default: 0): Maximum time in milliseconds for all retry attempts to complete. If exceeded, throws a Timeout Error. Must be greater than delay. Set to 0 to disable.
    • recovery (Function, default: () => Promise.resolve()): Function called after each failed attempt, before the next retry. Receives the same arguments as the task.
    • onError (Function, default: () => {}): Function called with each error that occurs. Useful for logging or monitoring.

Returns

A wrapped function that accepts the same arguments as the original task and returns a Promise.

Errors

If all retry attempts fail, the function throws an AggregateError containing all errors that occurred during the retry attempts.

Examples

Retry with Exponential Backoff

const tekrar = require('tekrar');

// Helper function to implement exponential backoff
const withExponentialBackoff = (fn, maxRetries = 5) => {
  let retries = 0;

  const execute = tekrar(fn, {
    count: maxRetries,
    delay: 0, // We'll handle the delay in the recovery function
    recovery: async (...args) => {
      const delay = Math.pow(2, retries) * 100; // Exponential backoff
      console.log(`Retrying in ${delay}ms...`);
      await new Promise((resolve) => setTimeout(resolve, delay));
      retries++;
    },
  });

  return execute;
};

// Usage
const fetchWithRetry = withExponentialBackoff(async (url) => {
  const response = await fetch(url);
  if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
  return response.json();
});

// Use the function
fetchWithRetry('https://api.example.com/data')
  .then((data) => console.log('Success:', data))
  .catch((error) => console.error('All retries failed:', error));

With Timeout

const tekrar = require('tekrar');

const fetchData = tekrar(
  async () => {
    const response = await fetch('https://api.example.com/data');
    if (!response.ok) throw new Error('API request failed');
    return response.json();
  },
  {
    count: 5,
    delay: 500,
    timeout: 3000, // Give up after 3 seconds total
    onError: (error) => {
      console.error('Attempt failed:', error.message);
    },
  },
);

try {
  const data = await fetchData();
  console.log('Data:', data);
} catch (error) {
  if (error.message === 'Timeout Error') {
    console.error('Operation timed out after 3 seconds');
  } else {
    console.error('All retries failed:', error);
  }
}

License

MIT

Author

Timur Sevimli svmlitimur@gmail.com

About

An abstraction for handling retry strategies, including exponential backoff and custom configurations, for operations that fail.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors