Skip to main content

Overview

The Backoffs class provides built-in backoff strategies for job retries and utilities for normalizing backoff options.

Built-in Strategies

fixed

Returns a fixed delay with optional jitter.
Backoffs.builtinStrategies.fixed(delay: number, jitter?: number)
delay
number
required
The fixed delay in milliseconds
jitter
number
default:"0"
Jitter factor (0-1) to randomize delay

Example

import { Queue } from 'bullmq';

const queue = new Queue('myQueue', {
  connection: { host: 'localhost', port: 6379 },
});

await queue.add(
  'task',
  { data: 'value' },
  {
    attempts: 3,
    backoff: {
      type: 'fixed',
      delay: 5000,      // 5 seconds
      jitter: 0.1,      // ±10% randomization
    },
  }
);

exponential

Returns an exponentially increasing delay with optional jitter.
Backoffs.builtinStrategies.exponential(delay: number, jitter?: number)
delay
number
required
The base delay in milliseconds
jitter
number
default:"0"
Jitter factor (0-1) to randomize delay
The delay formula is: delay * 2^(attemptsMade - 1)

Example

await queue.add(
  'task',
  { data: 'value' },
  {
    attempts: 5,
    backoff: {
      type: 'exponential',
      delay: 1000,     // Base delay: 1 second
      jitter: 0.2,     // ±20% randomization
    },
  }
);

// Retry delays (approximate):
// Attempt 1: 1000ms (1 * 2^0)
// Attempt 2: 2000ms (1 * 2^1)
// Attempt 3: 4000ms (1 * 2^2)
// Attempt 4: 8000ms (1 * 2^3)
// Attempt 5: 16000ms (1 * 2^4)

Static Methods

normalize

Normalizes a backoff value to BackoffOptions.
static normalize(
  backoff: number | BackoffOptions
): BackoffOptions | undefined
backoff
number | BackoffOptions
required
Backoff configuration (number for fixed delay or BackoffOptions object)
// Number is normalized to fixed backoff
const opts1 = Backoffs.normalize(5000);
// { type: 'fixed', delay: 5000 }

// BackoffOptions is returned as-is
const opts2 = Backoffs.normalize({
  type: 'exponential',
  delay: 1000,
});
// { type: 'exponential', delay: 1000 }

calculate

Calculates the delay for a given attempt.
static calculate(
  backoff: BackoffOptions,
  attemptsMade: number,
  err: Error,
  job: MinimalJob,
  customStrategy?: BackoffStrategy
): Promise<number> | number | undefined
backoff
BackoffOptions
required
Backoff configuration
attemptsMade
number
required
Number of attempts already made
err
Error
required
The error that caused the failure
job
MinimalJob
required
The job being retried
customStrategy
BackoffStrategy
Custom backoff strategy function

BackoffOptions

interface BackoffOptions {
  type: string;      // 'fixed', 'exponential', or custom type
  delay?: number;    // Delay in milliseconds
  jitter?: number;   // Jitter factor (0-1)
}

Custom Backoff Strategy

You can implement a custom backoff strategy:
import { Queue, Worker } from 'bullmq';

// Define custom strategy
const customBackoff = (
  attemptsMade: number,
  type: string,
  err: Error,
  job: any
) => {
  // Custom logic here
  if (err.message.includes('rate-limit')) {
    return 60000; // 1 minute for rate limit errors
  }
  return attemptsMade * 2000; // Linear backoff otherwise
};

// Register in worker settings
const worker = new Worker(
  'myQueue',
  async (job) => {
    // Process job
  },
  {
    connection: { host: 'localhost', port: 6379 },
    settings: {
      backoffStrategy: customBackoff,
    },
  }
);

// Use in job options
await queue.add(
  'task',
  { data: 'value' },
  {
    attempts: 5,
    backoff: {
      type: 'custom',  // Your custom type name
    },
  }
);

Jitter Calculation

When jitter is specified, the actual delay is randomized:
const minDelay = delay * (1 - jitter);
const maxDelay = delay * (1 + jitter);
const actualDelay = random(minDelay, maxDelay);
For example, with delay: 1000 and jitter: 0.2:
  • Minimum delay: 800ms
  • Maximum delay: 1200ms

Examples

Simple Fixed Backoff

await queue.add(
  'email',
  { to: '[email protected]' },
  {
    attempts: 3,
    backoff: 5000, // 5 seconds between retries
  }
);

Exponential Backoff with Jitter

await queue.add(
  'api-call',
  { endpoint: '/users' },
  {
    attempts: 5,
    backoff: {
      type: 'exponential',
      delay: 2000,
      jitter: 0.3, // ±30% randomization
    },
  }
);

Error-Specific Backoff

const errorAwareBackoff = (
  attemptsMade: number,
  type: string,
  err: Error
) => {
  if (err.name === 'NetworkError') {
    return 30000; // 30 seconds for network errors
  }
  if (err.name === 'ValidationError') {
    return -1; // Don't retry validation errors
  }
  // Default exponential backoff
  return Math.pow(2, attemptsMade - 1) * 1000;
};

const worker = new Worker('myQueue', processor, {
  connection: { host: 'localhost', port: 6379 },
  settings: {
    backoffStrategy: errorAwareBackoff,
  },
});

Build docs developers (and LLMs) love