philiprehberger / http-retry-client
HTTP client wrapper with automatic retries, exponential backoff, and jitter
Package info
github.com/philiprehberger/http-retry-client
pkg:composer/philiprehberger/http-retry-client
v1.0.2
2026-03-17 20:06 UTC
Requires
- php: ^8.2
Requires (Dev)
- laravel/pint: ^1.0
- phpstan/phpstan: ^1.12|^2.0
- phpunit/phpunit: ^11.0
Suggests
- psr/http-client: For PSR-18 HTTP client integration (^1.0)
README
HTTP client wrapper with automatic retries, exponential backoff, and jitter. Framework-agnostic with zero dependencies beyond PHP 8.2.
Requirements
- PHP ^8.2
Installation
composer require philiprehberger/http-retry-client
Usage
Basic Usage
Implement the HttpExecutor interface to wrap your preferred HTTP client:
use PhilipRehberger\HttpRetry\Contracts\HttpExecutor; use PhilipRehberger\HttpRetry\HttpRequest; use PhilipRehberger\HttpRetry\HttpResponse; use PhilipRehberger\HttpRetry\RetryClient; class CurlExecutor implements HttpExecutor { public function execute(HttpRequest $request): HttpResponse { $ch = curl_init($request->url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $request->method); if ($request->body !== null) { curl_setopt($ch, CURLOPT_POSTFIELDS, $request->body); } $body = curl_exec($ch); $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return new HttpResponse($statusCode, $body); } } $client = new RetryClient(new CurlExecutor()); $result = $client->send(new HttpRequest('GET', 'https://api.example.com/data')); if ($result->successful()) { echo $result->body; }
Custom Retry Policy
use PhilipRehberger\HttpRetry\RetryClient; use PhilipRehberger\HttpRetry\RetryPolicy; $policy = new RetryPolicy( maxRetries: 5, baseDelayMs: 200, maxDelayMs: 30000, multiplier: 2.0, jitter: true, retryableStatusCodes: [429, 500, 502, 503, 504], ); $client = new RetryClient($executor, $policy);
Fluent Builder
use PhilipRehberger\HttpRetry\RetryPolicy; $policy = RetryPolicy::builder() ->maxRetries(5) ->baseDelay(200) ->maxDelay(30000) ->multiplier(3.0) ->withoutJitter() ->retryOn([500, 502, 503]) ->build();
Handling Retry Results
use PhilipRehberger\HttpRetry\Exceptions\MaxRetriesExceededException; try { $result = $client->send($request); echo "Status: {$result->statusCode}\n"; echo "Attempts: {$result->attempts}\n"; echo "Total delay: {$result->totalDelayMs}ms\n"; echo "Was retried: " . ($result->wasRetried ? 'yes' : 'no') . "\n"; } catch (MaxRetriesExceededException $e) { echo "Failed after {$e->attempts} attempts: {$e->getMessage()}\n"; }
Custom Retryable Status Codes
$policy = RetryPolicy::builder() ->retryOn([408, 429, 500, 502, 503, 504]) ->build();
API
RetryPolicy
| Parameter | Type | Default | Description |
|---|---|---|---|
maxRetries |
int |
3 |
Maximum number of retry attempts |
baseDelayMs |
int |
100 |
Base delay in milliseconds |
maxDelayMs |
int |
10000 |
Maximum delay cap in milliseconds |
multiplier |
float |
2.0 |
Backoff multiplier |
jitter |
bool |
true |
Whether to add random jitter |
retryableStatusCodes |
array<int> |
[429, 500, 502, 503, 504] |
Status codes that trigger a retry |
RetryClient
| Method | Description |
|---|---|
send(HttpRequest $request): RetryResult |
Send a request with automatic retries |
RetryResult
| Property | Type | Description |
|---|---|---|
statusCode |
int |
HTTP status code of the final response |
body |
string |
Response body |
headers |
array |
Response headers |
attempts |
int |
Total number of attempts made |
totalDelayMs |
int |
Total delay spent waiting (ms) |
wasRetried |
bool |
Whether the request was retried |
successful() |
bool |
Whether the status code is 2xx |
HttpExecutor (Interface)
| Method | Description |
|---|---|
execute(HttpRequest $request): HttpResponse |
Execute an HTTP request |
MaxRetriesExceededException
| Property | Type | Description |
|---|---|---|
attempts |
int |
Total number of attempts made |
Development
composer install vendor/bin/phpunit vendor/bin/pint --test vendor/bin/phpstan analyse
License
MIT