caseyamcl/guzzle_retry_middleware
Guzzle middleware that automatically retries failed HTTP requests with configurable delays and retry conditions. Helps handle transient network errors, 5xx responses, and rate limiting with backoff strategies, improving resilience without changing client code.
delay option aligns with modern async-friendly HTTP patterns.Http facade or GuzzleHttp\Client). No architectural friction; leverages Guzzle’s built-in concurrency support.GuzzleHttp\Pool). Previously, usleep could stall parallel workers; now uses Guzzle’s delay option, which is async-compatible.
$client = new Client([
'middleware' => [new RetryMiddleware()],
'delay' => 100, // Milliseconds between retries (non-blocking)
]);
delay, max_retries) via a provider, injecting the client into Laravel’s container.Http facade, wrap with withOptions():
Http::withOptions(['middleware' => [new RetryMiddleware()], 'delay' => 200]);
delay option in future versions.GuzzleHttp\HandlerStack or mocks to simulate delays/retries.GuzzleHttp\Pool, Laravel Jobs) where non-blocking delays are critical?delay be globally set (via service provider) or per-request (e.g., sensitive APIs with shorter delays)?spatie/fractal for resilience.Http facade, how to inject middleware without breaking existing delay usage (if any)?GuzzleHttp\Pool, Laravel Jobs, or spatie/async packages.GuzzleHttp\Client, Http facade).fruitcake/laravel-cors, spatie/array-to-xml).GuzzleHttp\Pool):
$pool = new Pool($client, $requests, [
'concurrency' => 10,
'fulfilled' => function (Response $response) { ... },
]);
delay option is stable.Http::withOptions() or by replacing the underlying client.delay and retry settings in config:
// config/guzzle.php
'retry' => [
'delay' => 200, // Non-blocking delay (ms)
'max_retries' => 3,
],
$client = new Client([
'middleware' => [new RetryMiddleware()],
'delay' => config('guzzle.retry.delay'),
]);
Http facade:
Http::withOptions([
'middleware' => [new RetryMiddleware()],
'delay' => config('guzzle.retry.delay'),
]);
GuzzleHttp\HandlerStack to mock delays/retries in parallel scenarios.delay and retry settings may need tuning for parallel workloads. Centralize in config files (e.g., config/guzzle.php).delay option changes. Pin versions if stability is critical.delay behavior.RetryMiddleware::setLogger(new \Monolog\Logger('guzzle_retries'));
delay causing unintended blocking (unlikely post-v2.13.0).POST/DELETE in parallel may cause race conditions.Sentry or Laravel Debugbar to trace failed retries in async contexts.delay is optimized.| Failure Scenario | Impact | Mitigation |
|---|---|---|
| API returns 429 in parallel bursts | Retry loop exhaustion | Circuit breaker (e.g., spatie/fractal). |
| Network timeout during retry | Increased latency, failed requests | Configure connect_timeout in Guzzle. |
| Backoff too short in parallel | Thundering herd on API | Exponential backoff with jitter. |
| Non-retryable 5xx in parallel | Unnecessary retries | Extend middleware to filter status codes. |
Guzzle delay option changes |
Breaking changes in future versions | Pin Guzzle version in composer.json. |
delay.PARALLEL_RETRIES.md detailing:
How can I help you explore Laravel packages today?