Overview

A job can fail for multiple reasons, such as network outage or bugs. That’s why Defer allows you to set up automatic retries for failed executions.

Before deep diving in the different retry strategies, it is important to understand the concept of idempotency. Idempotency means that a job can be safely executed multiple times, which is crucial since a job may be half-processed, throw an error, and then be re-executed repeatedly.

In general you can consider your function idempotent if:

  • it can safely run multiple times with the same arguments
  • side effects are expected to happen only once

Defer allows you to configure two types of retry strategies: the exponential backoff strategy and the linear retry strategy.

Exponential backoff

In a backoff retry strategy, the system increases the delay between consecutive retries after each attempt. The delay is increasing exponentially. This approach helps prevent overwhelming the service with too many retries in quick succession, and it gives the service more time to recover from transient issues.

Linear

In a linear retry strategy, the system retries the operation with a consistent delay between attempts. For example, the system might retry the operation with a interval of 5 seconds between each attempts.

Choosing the right strategy

Here is a simple diagram to assist you in deciding which strategy to apply.

strategy decision tree

You can find more information on how to use different retry strategies in our dedicated blog post.

Configuration

The retry behavior is set up using the following key.

FieldTypeDefaultDescription
maxAttemptsInteger0How many retries should we attempt in total
initialIntervalInteger30How close the first retry should be? (in seconds)
randomizationFactorFloat0.5How much randomness should be introduced in the space between retries.
multiplierFloat1.5How fast the space between each retry should grow? (exponential back-off).
maxIntervalInteger600What should be the max space between 2 retries? (in seconds)

Examples

import { defer } from "@defer/client";

async function sendEmail(endpoint: string, data: any) {
  // business logic here
}

export default defer(sendEmail, { retry: true });