Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Backoff

Backoff is a strategy that increases the delay between successive retries of a failed operation, instead of retrying immediately or at a fixed interval.

The most common form is exponential backoff, where the delay grows exponentially with each failed attempt, for example doubling after every failure: 1 second, 2 seconds, 4 seconds, 8 seconds, and so on, usually capped at a maximum delay so the wait does not grow unbounded. The rationale is that a failure is often caused by a temporarily overloaded or unavailable service, and hammering it with immediate retries only makes the problem worse, while a growing delay gives the service time to recover before the next attempt.

Backoff is almost always combined with jitter, a small random variation added to the computed delay. Without jitter, many clients that failed at the same time, for instance after a service restart, would all retry in lockstep at exactly the same moments, producing repeated bursts of load known as the thundering herd problem. Adding randomness spreads those retries out over time instead. Backoff is also typically paired with a maximum number of attempts, or a deadline, after which the operation is abandoned and reported as failed, rather than retried forever.

Backoff logic is commonly implemented by hand around HTTP client calls, or provided by libraries built on top of Guzzle middleware, message queue workers, or job retry mechanisms in frameworks such as Laravel, where a job’s backoff() method or attribute controls the delay before each re-attempt.

<?php

    function withBackoff(callable $operation, int $maxAttempts = 5): mixed {
        $attempt = 0;
        while (true) {
            try {
                return $operation();
            } catch (\Throwable $e) {
                $attempt++;
                if ($attempt >= $maxAttempts) {
                    throw $e;
                }
                $delay = (2 ** $attempt) + random_int(0, 1000) / 1000;
                usleep((int) ($delay * 1_000_000));
            }
        }
    }

?>

Documentation

See Also