exponential-backoff

repository·master·Indexed 19 days ago

https://github.com/coveooss/exponential-backoff

A utility for retrying promise-returning functions with an exponential delay between attempts to handle transient failures in asynchronous operations. It features the `backOff` function and `BackOffOptions` for customizing the number of attempts, delay timing, jitter, and custom retry logic.

Tokens
2.4K
Snippets
8
Records
11
Agent score
63%

What's inside exponential-backoff

  1. Migrate from v2 to v3

    master

    When upgrading from version 2 to version 3, note the following breaking change regarding jitter configuration:

    • Jitter Configuration: The jitter option now accepts a union string type to simplify configuration. As a result, the JitterTypes enum is no longer available and should be replaced with the corresponding string literals.
  2. Migrate from v1 to v2

    master

    When upgrading from version 1 to version 2, note the following breaking changes in the backOff<T> function and its options:

    • Function Signature: The first argument of backOff<T> is now exclusively the function you want to back off. The retry function has been moved and is now available as a property within the IBackOffOptions object.
    • Default Delay: The default value for the delayFirstAttempt option has changed from its previous behavior to false.
  3. Use the backOff function to retry promises

    master

    The backOff<T> function wraps a promise-returning function and retries it with an exponential delay between attempts. It returns a Promise<T> that resolves with the result of the successful function call or rejects if all retry attempts fail or the retry logic returns false.

    import { backOff } from "exponential-backoff";
    
    function getWeather() {
      return fetch("weather-endpoint");
    }
    
    async function main() {
      try {
        const response = await backOff(() => getWeather());
        // process response
      } catch (e) {
        // handle error
      }
    }
    
    main();
  4. Reference BackOffOptions configuration keys

    master

    The following options are available in the BackOffOptions object:

    interface BackOffOptions {
      /** Decides whether the startingDelay should be applied before the first call. Default: false */
      delayFirstAttempt?: boolean;
    
      /** Decides whether a jitter should be applied to the delay. Possible values: 'full', 'none'. Default: 'none' */
      jitter?: 'full' | 'none' | string;
    
      /** The maximum delay, in milliseconds, between two consecutive attempts. Default: Infinity */
      maxDelay?: number;
    
      /** The maximum number of times to attempt the function. Default: 10. Minimum: 1 */
      numOfAttempts?: number;
    
      /** Logic run after every failed attempt. Receives (error, attemptNumber). Return true to continue, false to stop. Default: always returns true */
      retry?: (e: any, attemptNumber: number) => boolean | Promise<boolean>;
    
      /** The delay, in milliseconds, before executing the function for the first time. Default: 100 */
      startingDelay?: number;
    
      /** The multiplier applied to the delay between reattempts. Default: 2 */
      timeMultiple?: number;
    }
  5. Use the retry function to control execution flow

    master

    The retry option allows you to implement custom logic after a failure. This is useful for logging errors or deciding whether a specific error type warrants a retry.

    • If the function returns true (or a Promise resolving to true), the library will attempt the next retry.
    • If the function returns false (or a Promise resolving to false), the execution stops immediately, even if numOfAttempts has not been reached.
    const options: BackoffOptions = {
      retry: (error, attemptNumber) => {
        console.error(`Attempt ${attemptNumber} failed:`, error);
        // Only retry if it's a network error
        return error.isNetworkError === true;
      }
    };
  6. Execute a function with exponential backoff using backOff()

    master

    The backOff function is the primary entrypoint for retrying promise-returning functions. It accepts a request function and an optional options object to customize retry behavior. The function will repeatedly attempt to execute the request until it succeeds, the maximum number of attempts is reached, or the provided retry logic determines that no further retries should occur.

    Returns a Promise that resolves to the result of the request function if successful, or throws the error encountered during the final attempt if all retries fail.

    import { backOff } from 'exponential-backoff';
    
    const result = await backOff(() => myAsyncFunction(), {
      // options here
    });
  7. Configure backoff behavior with BackoffOptions

    master

    When calling backOff, you can provide a BackoffOptions object to control how retries are handled. The available options are defined by the BackoffOptions and IBackOffOptions interfaces.

    Key behaviors controlled by options include:

    • Number of attempts: Limiting how many times the function is executed.
    • Retry logic: A custom retry function that receives the error and the current attempt number to decide if a retry should proceed.
    • Delay strategy: Determining how long to wait between attempts (managed via the DelayFactory).
    import { backOff, BackoffOptions } from 'exponential-backoff';
    
    const options: BackoffOptions = {
      // implementation of BackoffOptions properties
    };
    
    await backOff(() => someTask(), options);
  8. Reference: JitterType values

    master

    The jitter option determines how randomness is applied to the delay to prevent thundering herd problems. Supported values are:

    • "none": No jitter is applied.
    • "full": Full jitter is applied (a random value between 0 and the current delay).
    type JitterType = "none" | "full";
  9. Reference: IBackOffOptions configuration keys

    master

    The following keys are available in the IBackOffOptions interface to configure the retry strategy:

    interface IBackOffOptions {
      /** Decides whether the `startingDelay` should be applied before the first call. Defaults to `false`. */
      delayFirstAttempt: boolean;
      /** Decides whether a jitter should be applied. Possible values: `"full"`, `"none"`. Defaults to `"none"`. */
      jitter: JitterType;
      /** The maximum delay, in milliseconds, between two consecutive attempts. Defaults to `Infinity`. */
      maxDelay: number;
      /** The maximum number of times to attempt the function. Must be at least `1`. Defaults to `10`. */
      numOfAttempts: number;
      /** 
       * Logic to run after every failed attempt. 
       * Called with `(e: any, attemptNumber: number)`. 
       * Return `true` to retry, `false` to stop. 
       * Defaults to a function that always returns `true`. 
       */
      retry: (e: any, attemptNumber: number) => boolean | Promise<boolean>;
      /** The delay, in milliseconds, before executing the function for the first time. Defaults to `100`. */
      startingDelay: number;
      /** The multiplier applied to the delay between reattempts. Defaults to `2`. */
      timeMultiple: number;
    }