Weave Code
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 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.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture Fit

  • Use Case Alignment: Continues to excel for Laravel applications requiring resilient HTTP clients, particularly in scenarios with parallel requests (e.g., batch API calls, webhook processing). The shift to Guzzle’s delay option aligns with modern async-friendly HTTP patterns.
  • Guzzle Integration: Remains native to Laravel’s HTTP stack (Guzzle-based Http facade or GuzzleHttp\Client). No architectural friction; leverages Guzzle’s built-in concurrency support.
  • Stateless Design: Retry logic remains encapsulated in middleware, preserving Laravel’s middleware stack pattern. No external dependencies or state.

Integration Feasibility

  • Parallel Requests Support: Critical fix for non-blocking delays in concurrent requests (e.g., 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)
    ]);
    
  • Laravel Service Provider: Can still centralize config (e.g., delay, max_retries) via a provider, injecting the client into Laravel’s container.
  • Existing Guzzle Usage: Trivial integration for apps using Guzzle directly. For Laravel’s Http facade, wrap with withOptions():
    Http::withOptions(['middleware' => [new RetryMiddleware()], 'delay' => 200]);
    

Technical Risk

  • Version Compatibility: Guzzle v7+ fully supported; Guzzle v8+ may require testing (no breaking changes yet). Risk: Potential edge cases with Guzzle’s delay option in future versions.
  • Retry Logic Complexity: Default retries on 429/503 unchanged, but parallel request handling now safer. Customization still requires understanding middleware config.
  • Backoff Strategy: Exponential backoff remains configurable but may need tuning for high-concurrency APIs (e.g., AWS, Stripe). Poor config could still cause thundering herd issues.
  • Testing Overhead: Non-deterministic retries persist in tests. Use GuzzleHttp\HandlerStack or mocks to simulate delays/retries.

Key Questions

  1. Parallel Requests: Does the app use concurrent HTTP calls (e.g., GuzzleHttp\Pool, Laravel Jobs) where non-blocking delays are critical?
  2. Configuration: Should delay be globally set (via service provider) or per-request (e.g., sensitive APIs with shorter delays)?
  3. Observability: How will retry delays be logged/monitored in async contexts (e.g., queue workers, parallel jobs)?
  4. Circuit Breaker: Still needed for repeated failures? Consider pairing with spatie/fractal for resilience.
  5. Dependency Isolation: For Laravel’s Http facade, how to inject middleware without breaking existing delay usage (if any)?

Integration Approach

Stack Fit

  • Laravel Ecosystem: Enhanced compatibility with:
    • Parallel Requests: Non-blocking delays now work seamlessly with GuzzleHttp\Pool, Laravel Jobs, or spatie/async packages.
    • Guzzle-based services (e.g., GuzzleHttp\Client, Http facade).
    • Third-party packages (e.g., fruitcake/laravel-cors, spatie/array-to-xml).
  • PHP Version: Compatible with Laravel’s PHP 8.0+ (no changes).
  • Composer Dependency: Lightweight (~1MB); no runtime dependencies beyond Guzzle.

Migration Path

  1. Assessment Phase:
    • Audit parallel HTTP usage (e.g., batch processing, webhooks, async jobs).
    • Identify endpoints where non-blocking delays are critical (e.g., high-throughput APIs).
  2. Proof of Concept:
    • Test middleware with parallel requests (e.g., GuzzleHttp\Pool):
      $pool = new Pool($client, $requests, [
          'concurrency' => 10,
          'fulfilled' => function (Response $response) { ... },
      ]);
      
    • Validate delay behavior under load (e.g., simulate 429 storms).
  3. Incremental Rollout:
    • Phase 1: Apply to parallel request workflows (e.g., bulk API calls).
    • Phase 2: Extend to high-impact async jobs (e.g., payment retries).
    • Phase 3: Global middleware (if justified) via service provider.

Compatibility

  • Guzzle v7/v8: Native support; delay option is stable.
  • Laravel Facades: Works with Http::withOptions() or by replacing the underlying client.
  • Middleware Stack: Compatible with Laravel’s pipeline (e.g., auth, logging).

Sequencing

  1. Configuration: Define delay and retry settings in config:
    // config/guzzle.php
    'retry' => [
        'delay' => 200, // Non-blocking delay (ms)
        'max_retries' => 3,
    ],
    
  2. Client Initialization:
    • For Guzzle:
      $client = new Client([
          'middleware' => [new RetryMiddleware()],
          'delay' => config('guzzle.retry.delay'),
      ]);
      
    • For Laravel’s Http facade:
      Http::withOptions([
          'middleware' => [new RetryMiddleware()],
          'delay' => config('guzzle.retry.delay'),
      ]);
      
  3. Testing: Use GuzzleHttp\HandlerStack to mock delays/retries in parallel scenarios.
  4. Deployment: Roll out in stages, monitoring retry rates and concurrency impact.

Operational Impact

Maintenance

  • Configuration Drift: delay and retry settings may need tuning for parallel workloads. Centralize in config files (e.g., config/guzzle.php).
  • Middleware Updates: Monitor Guzzle major versions for delay option changes. Pin versions if stability is critical.
  • Deprecation Risk: Low (MIT license, active maintenance). Track Guzzle v8+ for delay behavior.

Support

  • Debugging Retries: Log retry delays with context (e.g., endpoint, attempt #, delay duration):
    RetryMiddleware::setLogger(new \Monolog\Logger('guzzle_retries'));
    
  • Common Issues:
    • Parallel Stalls: Misconfigured delay causing unintended blocking (unlikely post-v2.13.0).
    • Backoff Too Short: High retry volume under load. Use exponential backoff with jitter.
    • Non-Idempotent Operations: Retrying POST/DELETE in parallel may cause race conditions.
  • Support Tools: Integrate with Laravel’s Sentry or Laravel Debugbar to trace failed retries in async contexts.

Scaling

  • Performance Impact: Non-blocking delays improve parallel request throughput. Minimal overhead if delay is optimized.
  • Load Testing: Simulate high-concurrency scenarios (e.g., 100 parallel retries) to validate:
    • Database connection pooling (if retries involve DB calls).
    • Queue workers (if retries are async).
  • Horizontal Scaling: Stateless retries scale automatically with Laravel’s architecture.

Failure Modes

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.

Ramp-Up

  • Developer Onboarding:
    • Document parallel request behavior (e.g., "This endpoint retries 3 times with 200ms delays in parallel calls").
    • Provide examples for:
      • Global middleware with delay.
      • Per-request customization (e.g., shorter delays for critical APIs).
      • Testing parallel retry scenarios.
  • Team Training:
    • Educate on idempotency in parallel retries (avoid race conditions).
    • Train on observability (logging delays, monitoring parallel jobs).
  • Documentation:
    • Add PARALLEL_RETRIES.md detailing:
      • Which workflows use parallel retries.
      • Expected delay behavior under concurrency.
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity