php 49 lines · 7 steps

Retry with exponential backoff in PHP

A small class that re-runs a failing operation with growing, jittered delays until it succeeds or gives up.

Explained by highlit
1<?php
2 
3namespace App\Support;
4 
5use Closure;
6use Throwable;
7 
8class Retryer
9{
10 public function __construct(
11 private int $maxAttempts = 5,
12 private int $baseDelayMs = 100,
13 private int $maxDelayMs = 10000,
14 private float $multiplier = 2.0,
15 ) {
16 }
17 
18 public function run(Closure $operation, ?Closure $shouldRetry = null): mixed
19 {
20 $attempt = 0;
21 
22 beginning:
23 try {
24 return $operation($attempt + 1);
25 } catch (Throwable $e) {
26 $attempt++;
27 
28 if ($attempt >= $this->maxAttempts) {
29 throw $e;
30 }
31 
32 if ($shouldRetry !== null && ! $shouldRetry($e)) {
33 throw $e;
34 }
35 
36 usleep($this->delayFor($attempt) * 1000);
37 goto beginning;
38 }
39 }
40 
41 private function delayFor(int $attempt): int
42 {
43 $exponential = $this->baseDelayMs * ($this->multiplier ** ($attempt - 1));
44 $capped = min($exponential, $this->maxDelayMs);
45 $jitter = random_int(0, (int) ($capped / 2));
46 
47 return (int) ($capped - $jitter);
48 }
49}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Exponential backoff with a cap keeps retries from hammering a struggling dependency while bounding the worst-case wait.
  2. 2Adding jitter spreads concurrent retries out so many clients don't all wake at the same instant.
  3. 3A retry predicate lets callers distinguish transient failures worth retrying from permanent ones that should fail fast.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Retry with exponential backoff in PHP — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code