guzzlehttp/retry-subscriber
A Guzzle subscriber that automatically retries failed HTTP requests using configurable strategies, including exponential backoff. Set retry limits, delays, and the exceptions or status codes that trigger a retry to make your Guzzle 6/7 API calls more resilient.
Architecture fit. guzzlehttp/retry-subscriber targets the Guzzle 4/5 event-subscriber architecture (Guzzle\Common\EventSubscriber, Guzzle\Plugin\*). Guzzle 6 replaced that entire extension model with the middleware stack (GuzzleHttp\Middleware::retry, handler composition). The package therefore does not plug into the HTTP layer that any currently supported Laravel release ships with — Laravel 7+ pins guzzlehttp/guzzle: ^7.0, and Laravel 6 pins ^6.5. There is no supported version of Laravel where this package is the natural integration point.
Integration feasibility. Low. Two independent blockers:
require is scoped to Guzzle 4/5 (guzzle/guzzle), while Laravel requires guzzlehttp/guzzle (the renamed, 6+ namespace). These are distinct package names — this is not a version bump, it is a fork boundary. Adoption means either pinning an EOL Laravel or hand-porting the code.Middleware::retry() in Guzzle 6/7 and as Http::retry($times, $sleep, $when) in Laravel's Illuminate\Http\Client. Any capability this package offers is already available with first-party support and security maintenance.Technical risk. High and mostly non-mitigable:
Key questions.
Middleware::retry() or Http::retry() + a custom $when closure? If not, the business case is zero.Verdict: treat as a reference implementation, not an adoption candidate. Low opportunity score with zero dependents is consistent with a superseded package, not an underappreciated one.
Stack fit. Poor by construction. Recommended target: do not add this dependency. Reimplement the intent on first-party primitives:
| Need | Native mechanism |
|---|---|
| Retry in Laravel HTTP client | Http::retry(3, 200, throw: false) |
| Retry in raw Guzzle 7 | HandlerStack + Middleware::retry() |
| Conditional retry | $when closure / decider callable |
| Exponential backoff | delay callable (1000 * 2 ** $attempt) |
Migration path. If legacy code already depends on the package, sequence it as a removal, not an upgrade:
RetrySubscriber, Guzzle\Plugin, guzzle/guzzle in composer.lock).RetryPolicy::shouldRetry() / delayFor()) so the transport library is swappable.Middleware::retry() (Guzzle 6/7) or Http::retry() behind that interface.composer why guzzle/guzzle must be empty) to prevent reintroduction.Compatibility. No forward-compatibility path exists — Guzzle 4/5 are EOL, do not run on PHP 8, and are not compatible with Laravel's HTTP layer. The only "compatible" scenario is a legacy application frozen on PHP 5.x/7.0 and Laravel ≤5.x, which is itself a remediation item.
Sequencing. Effort is hours-to-days, not a project. Do it opportunistically the next time the affected code path is touched, bundled with an unrelated change, rather than as a standalone initiative. If a legacy Guzzle 5 service exists, its own migration is the real workstream; this package is a leaf node in it.
Maintenance. Effectively 100% internal ownership on day one — archived upstream means no patch stream. Estimate: a permanent low-grade ownership tax plus unbounded cost if a retry-related incident lands on it. Contrast with the native middleware, where maintenance is bundled into routine Guzzle/Laravel upgrades already on the roadmap.
Support. No maintainer, no issue triage, no CVE channel. Any advisory against Guzzle 4/5 requires you to independently assess exposure and backport. Security review will flag archived dependencies; expect friction at every subsequent audit.
Scaling. Retry logic interacts badly with scale if unconstrained: naive retries multiply load on a degraded dependency (retry storms), and can exhaust PHP-FPM workers on Laravel queues where each retry holds a worker. Native middleware shares this risk, but with the advantage of an actively maintained delay/decider API and documented idempotency guidance. Note the package's own design predates Guzzle's Retry-After handling — you will likely hand-roll that.
Failure modes.
--ignore-platform-reqs or replace tricks, the subscriber may never be wired into the stack — retries silently don't happen and nobody notices until an incident review.Ramp-up. Near-zero learning cost (the API is simple), but that is a trap: the low ramp-up makes it look cheap while deferring the real cost to maintenance and incident response. Engineers unfamiliar with Guzzle 4/5 subscribers lose time on a dead architecture with no current documentation.
Recommendation to stakeholders: decline adoption; budget a small remediation task to replace any existing usage with first-party retry middleware, and record the archived-dependency policy gap this surfaced.
How can I help you explore Laravel packages today?