Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Guzzle Retry Middleware Laravel Package

caseyamcl/guzzle_retry_middleware

Guzzle Retry Middleware automatically retries Guzzle HTTP requests when servers return 429 or 503, or when requests time out. It honors Retry-After headers, backs off exponentially, supports configurable retry limits and callbacks, and drops into your handler stack with no setup.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

  • Reliability feature work (build vs. buy): Adopt instead of hand-rolling retry/back-off logic in every service class. The package already encodes the decisions teams usually get wrong: honoring Retry-After, exponential back-off when the header is absent, and a cap on attempts.
  • Third-party integration hardening: Any roadmap item that depends on an external API (payments, shipping, CRM sync, LLM providers, webhooks fan-out) turns "vendor returns 429/503" from a support ticket into an automatic, bounded retry. This is the cheapest resilience win available for outbound HTTP.
  • [Roadmap] Queue/worker stability: Retries at the HTTP layer reduce failed jobs, alert noise, and manual re-run toil — a direct input into SLO/error-budget conversations.
  • [Roadmap] Rate-limit etiquette: For partners who publish Retry-After, honoring it is a contractual and reputational requirement. This middleware makes compliance the default rather than a per-integration negotiation.
  • Observability groundwork: on_retry_callback is the hook for metrics (retry count by host/status), which supports decisions like "should we cache this vendor response?" or "is this integration degrading?"
  • Configuration strategy decisions: Options can be set at client, middleware, or per-request scope with documented precedence — enabling a sensible platform default while letting individual features opt out (retry_enabled => false for non-idempotent calls).
  • Non-goal confirmation: This is not a circuit breaker, not a queue, not a cache. Deciding not to use it as those things prevents architectural overreach.

When to Consider This Package

Adopt when:

  • The application makes outbound HTTP calls through Guzzle (directly, or via a Laravel/Guzzle handler stack you control) to services that can rate-limit or transiently fail.
  • You need spec-aligned behavior without writing it: 429/503 defaults, Retry-After parsing (including date format), exponential fallback, max attempts.
  • You want timeout/connection-reset retries (retry_on_timeout, Curl error 104) — the built-in Guzzle middleware does not cover this breadth.
  • You need per-request control (retry_enabled, max_retry_attempts => 0, retry_on_methods, should_retry_callback) so that safe methods retry and non-idempotent ones do not.
  • You need retry visibility for logging/metrics via on_retry_callback and expose_retry_header.
  • You want a small, auditable, MIT-licensed dependency with a changelog, tagged releases, high test coverage, and static analysis — i.e. low vendor risk.

Look elsewhere or pause when:

  • Version alignment is unproven. Current releases target Guzzle v8; Guzzle 6/7 (which many Laravel versions ship) require pinning ^2. Confirm the matrix before committing — this is the single biggest adoption risk.
  • Laravel's first-party Http::retry() already covers the need. If retry semantics are simple and confined to Laravel's HTTP client, the framework feature may be sufficient; this package earns its place when you need Retry-After parsing, timeout retries, callbacks, or a raw Guzzle stack.
  • You expect the package to buy you throughput or circuit-breaking. It retries; it does not shed load. Retrying without jitter, caps, or a breaker can amplify an outage — use give_up_after_secs/max_allowable_timeout_secs and pair with a breaker if that's the actual need.
  • Requests are non-idempotent (POST creating charges/orders) and you cannot guarantee server-side idempotency keys. Retries there risk duplicates; restrict via retry_on_methods or disable per request.
  • You need active maintainer support/SLA. 222 stars and zero dependents signal a healthy but single-maintainer project — fine for a utility, not something to route revenue-critical traffic through without a fork/patch plan.
  • You're not on Guzzle at all (Symfony HttpClient, cURL wrappers) — the middleware is handler-stack-specific.

How to Pitch It (Stakeholders)

For executives: This is a small, free, MIT-licensed component that makes our outbound API calls retry automatically when a partner is briefly unavailable or rate-limiting us. It converts a class of user-visible failures and on-call pages into silent, bounded recoveries — measured in minutes of engineering time rather than a project. Cost is one Composer dependency; risk is low (active releases, high test coverage, permissive license) with one caveat: we must verify Guzzle version compatibility before rollout, and it does not replace monitoring or circuit breaking.

For engineering: Drop GuzzleRetryMiddleware::factory() onto the handler stack and you get spec-aligned defaults: retry on 429/503, honor Retry-After when present, exponential back-off (1.5 × attempt) when it isn't, 10-attempt ceiling, optional timeout/connection-reset retries, and an on_retry_callback for structured logging and metrics. Configuration resolves predictably — per-request beats client constructor beats middleware factory — so we can set a platform-wide default and still let individual features opt out (retry_enabled => false) or narrow behavior (retry_on_methods, retry_on_status, retry_only_if_retry_after_header). Two action items before we ship it: pin the correct major (^2 for Guzzle 6/7, current release for Guzzle 8) and set max_allowable_timeout_secs / give_up_after_secs so retries can't stack into long-held workers. Add an on_retry_callback that emits a counter tagged by host and status — that single hook gives us the data to decide later whether a partner needs caching, a breaker, or a renegotiated rate limit.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
ably/pubsub-server
mstfkhazaal/defender
mfonte/base62x
karnoweb/metapilot
tobya/bcsapiwrapper
swalker2/cpanel
vish4395/laravel-translation-manager
morningtrain/economic
teksite/systeminfo-laravel
atomcms/voting
run6/weather
siokas/laravelembeddirectives
adamlien/pkuuids
gilsonsouza/lara-doc-generator
manelgavalda/enrollment_mobile
unabomber/timezone
delatbabel/contacts
astritzeqiri/g-recaptcha
kevinongko/laravel-genode
developeruz/laravel-analytics