Tiny PHP library providing retry functionality with multiple backoff strategies and jitter support.
- 4 retry strategies (plus the ability to use your own)
- Optional jitter/randomness to spread out retries and minimize collisions
- Wait time cap to limit maximum retry delays
- Custom callbacks for retry logic and error handling
- Type-safe with strict typing and comprehensive test coverage
- Backward compatible with stechstudio/backoff
- PHP 8.2 or higher
This library is a modernized fork of stechstudio/backoff with several improvements:
- Strict typing and comprehensive test coverage
- Explicit configuration instead of global static defaults
- Better naming - "retry" terminology instead of "backoff"
- Enhanced jitter control with
setJitterPercent()andsetJitterMinCap()methods - Backward compatibility through aliases
composer require jbzoo/retryThis library provides sane defaults for immediate use. By default: quadratic strategy with 100ms base time (attempt^2 * 100), maximum 5 retries, and no jitter.
The simplest way to use Retry is with the retry helper function:
use function JBZoo\Retry\retry;
$result = retry(function() {
return doSomeWorkThatMightFail();
});If successful $result will contain the result of the closure. If max attempts are exceeded the inner exception is re-thrown.
You can of course provide other options via the helper method if needed.
Parameters: $callback, $maxAttempts, $strategy, $waitCap, $useJitter.
Constructor parameters: $maxAttempts, $strategy, $waitCap, $useJitter.
use JBZoo\Retry\Retry;
$retry = new Retry(10, 'exponential', 10000, true);
$result = $retry->run(function() {
return doSomeWorkThatMightFail();
});For dependency injection scenarios, use chainable setters:
use JBZoo\Retry\Retry;
$result = (new Retry())
->setStrategy('constant')
->setMaxAttempts(10)
->enableJitter()
->run(function() {
return doSomeWorkThatMightFail();
});This library enforces explicit configuration over global defaults. Unlike the original library, static configuration variables are deprecated and disabled. This design choice ensures:
- Different parts of your project can have completely different retry settings
- No conflicts with third-party libraries using their own defaults
- Clear, explicit dependency injection patterns
Use dependency injection or direct instantiation instead of global configuration.
Four built-in strategies are available, each with a default base time of 100 milliseconds:
Sleeps for a fixed time on each retry.
use JBZoo\Retry\Strategies\ConstantStrategy;
$strategy = new ConstantStrategy(500); // 500ms each retrySleep time increases linearly: attempt × baseTime.
use JBZoo\Retry\Strategies\LinearStrategy;
$strategy = new LinearStrategy(200); // 200ms, 400ms, 600ms...Sleep time follows polynomial growth: (attempt^degree) × baseTime.
use JBZoo\Retry\Strategies\PolynomialStrategy;
$strategy = new PolynomialStrategy(100, 3); // (attempt^3) × 100ms
// Default degree is 2 (quadratic): 100ms, 400ms, 900ms...Sleep time grows exponentially: (2^attempt) × baseTime.
use JBZoo\Retry\Strategies\ExponentialStrategy;
$strategy = new ExponentialStrategy(100); // 200ms, 400ms, 800ms...use JBZoo\Retry\Retry;
use function JBZoo\Retry\retry;
retry(fn() => doWork(), 10, 'constant'); // Uses ConstantStrategy with 100ms default
$retry = new Retry(10, 'constant');use JBZoo\Retry\Retry;
use JBZoo\Retry\Strategies\LinearStrategy;
use function JBZoo\Retry\retry;
retry(fn() => doWork(), 10, new LinearStrategy(500));
$retry = new Retry(10, new LinearStrategy(500));Passing an integer creates a ConstantStrategy with that base time:
retry(fn() => doWork(), 10, 1000); // 1000ms constant delay
$retry = new Retry(10, 1000);Define your own strategy with a closure:
// Closure receives attempt number and returns sleep time in milliseconds
retry(fn() => doWork(), 10, fn($attempt) => (100 * $attempt) + 5000);
$retry = new Retry(10);
$retry->setStrategy(fn($attempt) => (100 * $attempt) + 5000);Limit maximum wait time for fast-growing strategies (like exponential):
retry(fn() => doWork(), 10, 'exponential', 5000); // Cap at 5 seconds
$retry = new Retry()->setWaitCap(5000);Prevent retry collisions by adding randomness to wait times. This is crucial when multiple clients might retry simultaneously.
retry(fn() => doWork(), 10, 'exponential', null, true); // Enable jitter
$retry = new Retry()->enableJitter();Fine-tune jitter behavior with additional methods:
$retry = new Retry()
->enableJitter()
->setJitterPercent(75) // Use 75% of calculated wait time as max
->setJitterMinCap(100); // Minimum jitter time of 100msBy default, this library uses "FullJitter" - a random time between 0 and the calculated wait time. See AWS's excellent explanation for more details.
Implement custom retry conditions beyond simple exception handling:
use JBZoo\Retry\Retry;
$retry = new Retry();
$retry->setDecider(function($attempt, $maxAttempts, $result, $exception = null) {
// Custom logic: retry based on time, specific exceptions, return values, etc.
return $attempt < 3 && ($exception instanceof SpecificException);
});Add logging or monitoring for retry attempts:
use JBZoo\Retry\Retry;
$retry = new Retry();
$retry->setErrorHandler(function($exception, $attempt, $maxAttempts) {
error_log("Retry {$attempt}/{$maxAttempts}: {$exception->getMessage()}");
});make update # Install dependencies
make test # Run PHPUnit tests
make codestyle # Run code quality checks
make test-all # Run both tests and code styleMIT
- CI-Report-Converter - Converting different error reports for deep compatibility with popular CI systems.
- Composer-Diff - See what packages have changed after
composer update. - Composer-Graph - Dependency graph visualization of composer.json based on mermaid-js.
- Mermaid-PHP - Generate diagrams and flowcharts with the help of the mermaid script language.
- Utils - Collection of useful PHP functions, mini-classes, and snippets for every day.
- Image - Package provides object-oriented way to manipulate with images as simple as possible.
- Data - Extended implementation of ArrayObject. Use files as config/array.
- SimpleTypes - Converting any values and measures - money, weight, exchange rates, length, ...