jbzoo / retry
Tiny PHP library providing retry functionality with multiple backoff strategies and jitter support
Installs: 67 616
Dependents: 1
Suggesters: 0
Security: 0
Stars: 8
Watchers: 1
Forks: 24
Open Issues: 0
README
Tiny PHP library providing retry functionality with multiple backoff strategies and jitter support.
Features
- 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
Requirements
- PHP 8.2 or higher
About This Fork
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
Installation
composer require jbzoo/retry
Quick Start
This library provides sane defaults for immediate use. By default: quadratic strategy with 100ms base time (attempt^2 * 100
), maximum 5 retries, and no jitter.
Simple Function Usage
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
.
Class-Based Usage
Constructor parameters: $maxAttempts
, $strategy
, $waitCap
, $useJitter
.
use JBZoo\Retry\Retry; $retry = new Retry(10, 'exponential', 10000, true); $result = $retry->run(function() { return doSomeWorkThatMightFail(); });
Fluent Interface
For dependency injection scenarios, use chainable setters:
use JBZoo\Retry\Retry; $result = (new Retry()) ->setStrategy('constant') ->setMaxAttempts(10) ->enableJitter() ->run(function() { return doSomeWorkThatMightFail(); });
Configuration Philosophy
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.
Retry Strategies
Four built-in strategies are available, each with a default base time of 100 milliseconds:
Constant Strategy
Sleeps for a fixed time on each retry.
use JBZoo\Retry\Strategies\ConstantStrategy; $strategy = new ConstantStrategy(500); // 500ms each retry
Linear Strategy
Sleep time increases linearly: attempt × baseTime
.
use JBZoo\Retry\Strategies\LinearStrategy; $strategy = new LinearStrategy(200); // 200ms, 400ms, 600ms...
Polynomial Strategy
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...
Exponential Strategy
Sleep time grows exponentially: (2^attempt) × baseTime
.
use JBZoo\Retry\Strategies\ExponentialStrategy; $strategy = new ExponentialStrategy(100); // 200ms, 400ms, 800ms...
Strategy Usage Options
String-Based Configuration
use JBZoo\Retry\Retry; use function JBZoo\Retry\retry; retry(fn() => doWork(), 10, 'constant'); // Uses ConstantStrategy with 100ms default $retry = new Retry(10, 'constant');
Instance-Based Configuration
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));
Integer-Based Configuration
Passing an integer creates a ConstantStrategy with that base time:
retry(fn() => doWork(), 10, 1000); // 1000ms constant delay $retry = new Retry(10, 1000);
Custom Closure Strategy
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);
Wait Cap
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);
Jitter
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();
Advanced Jitter Control
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 100ms
By default, this library uses "FullJitter" - a random time between 0 and the calculated wait time. See AWS's excellent explanation for more details.
Advanced Usage
Custom Retry Logic
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); });
Error Handling
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()}"); });
Development
Running Tests
make update # Install dependencies make test # Run PHPUnit tests make codestyle # Run code quality checks make test-all # Run both tests and code style
License
MIT
See Also
- 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, ...