3dgoo/laravel-http-timeout-retry-provider

Http timeout retry provider for Laravel

1.1.2 2025-06-25 07:55 UTC

README

A Laravel package that adds retry functionality to Http requests with configurable timeout handling and HTTP method filtering.

Features

  • Adds a withTimeoutRetry() macro to Laravel's HTTP client
  • Retries requests on ConnectionException (timeout) and other configurable exceptions
  • Http method filtering - Configure which methods (GET, POST, etc.) are safe to retry
  • Configurable retry attempts, delay, and enable/disable via config or environment variables
  • Optional logging of retry attempts with configurable log levels and channels
  • Runtime parameter overrides for fine-grained control

Installation

Require the package via Composer:

composer require 3dgoo/laravel-http-timeout-retry-provider

The service provider will be auto-discovered by Laravel.

Configuration

You can publish the configuration file:

php artisan vendor:publish --provider="X3dgoo\HttpTimeoutRetryProvider\Providers\HttpTimeoutRetryProvider" --tag=config

Or, set the following environment variables in your .env file:

HTTP_RETRY_ENABLED=true
HTTP_RETRY_ATTEMPTS=3
HTTP_RETRY_DELAY=100
HTTP_RETRY_ALLOWED_METHODS=GET,HEAD,OPTIONS
HTTP_RETRY_LOGGING_ENABLED=false
HTTP_RETRY_LOGGING_LEVEL=info
HTTP_RETRY_LOGGING_CHANNEL=

Configuration Options

  • HTTP_RETRY_ENABLED: Master switch to enable/disable retry functionality
  • HTTP_RETRY_ATTEMPTS: Number of retry attempts (0-100)
  • HTTP_RETRY_DELAY: Base delay between retries in milliseconds (minimum 10ms)
  • HTTP_RETRY_ALLOWED_METHODS: Comma-separated list of HTTP methods allowed for retry
  • HTTP_RETRY_LOGGING_ENABLED: Enable logging of retry attempts
  • HTTP_RETRY_LOGGING_LEVEL: Log level for retry messages
  • HTTP_RETRY_LOGGING_CHANNEL: Custom log channel (optional)

Usage

Basic Usage

Use the withTimeoutRetry() macro on any HTTP client request:

use Illuminate\Support\Facades\Http;

// Will retry GET requests (safe method)
$response = Http::withTimeoutRetry()->get('https://api.example.com/data');

// Will NOT retry POST requests by default (unsafe method)
$response = Http::withTimeoutRetry()->post('https://api.example.com/create', $data);

Advanced Usage with Parameters

Override default settings for specific requests:

Http::withTimeoutRetry(
    attempts: 5,
    delay: 250,
    callback: function ($exception) {
        return $exception instanceof \RuntimeException;
    },
    logRetries: true, 
    allowedMethods: ['POST', 'PUT']
)->post('https://api.example.com/create', $data);

HTTP Method Filtering

By default, only safe HTTP methods are retried to prevent unintended side effects:

// These methods are retried by default (safe, idempotent):
Http::withTimeoutRetry()->get('https://api.example.com/data');
Http::withTimeoutRetry()->head('https://api.example.com/check');
Http::withTimeoutRetry()->options('https://api.example.com/');

// These methods are NOT retried by default (potentially unsafe):
Http::withTimeoutRetry()->post('https://api.example.com/create');
Http::withTimeoutRetry()->put('https://api.example.com/update');
Http::withTimeoutRetry()->delete('https://api.example.com/item');

Overriding Method Filtering

When you need to retry unsafe methods, override at runtime:

// Allow specific methods for this request
Http::withTimeoutRetry(
    allowedMethods: ['POST', 'PUT']
)->post('https://api.example.com/idempotent-create', $data);

// Allow all methods for this request
Http::withTimeoutRetry(
    allowedMethods: ['*']
)->delete('https://api.example.com/resource/123');

Method Safety Guide

Different HTTP methods have different safety characteristics:

✅ Safe Methods (Default retry enabled)

  • GET, HEAD, OPTIONS: Idempotent and safe, no side effects
  • These are the recommended defaults for retry

⚠️ Potentially Unsafe Methods (Require explicit opt-in)

  • POST: Not idempotent, may create duplicate resources
  • PUT: Idempotent by spec, but implementation varies
  • PATCH: Not idempotent, partial updates can cause issues
  • DELETE: Idempotent but potentially destructive

Configuration Examples

// Safe methods only (recommended default)
'allowed_methods' => ['GET', 'HEAD', 'OPTIONS'],

// All read operations
'allowed_methods' => ['GET', 'HEAD', 'OPTIONS'],

// Include idempotent write operations (use with caution)
'allowed_methods' => ['GET', 'HEAD', 'OPTIONS', 'PUT'],

// All methods (not recommended as default)
'allowed_methods' => ['*'],

Logging

When logging is enabled, retry attempts are logged with detailed information including the HTTP method:

  • Log Level: Configurable via HTTP_RETRY_LOGGING_LEVEL (default: info)
  • Log Channel: Configurable via HTTP_RETRY_LOGGING_CHANNEL (uses default log channel if not set)
  • Log Message: Includes HTTP method, attempt number, total attempts, URL, and exception details

Example log entry:

[2025-06-25 12:00:00] local.info: HTTP GET request retry attempt 1/3 failed for URL https://api.example.com/create: Connection timeout
{
    "attempt": 1,
    "total_attempts": 3,
    "exception_class": "Illuminate\\Http\\Client\\ConnectionException",
    "exception_message": "Connection timeout",
    "request_url": "https://api.example.com/create",
    "request_method": "GET"
}

Configuration File

Default config (config/http.php):

return [
    'retry' => [
        'enabled' => env('HTTP_RETRY_ENABLED', true),
        'attempts' => max(0, min(100, env('HTTP_RETRY_ATTEMPTS', 3))),
        'delay' => max(10, env('HTTP_RETRY_DELAY', 100)),
        'allowed_methods' => array_map('strtoupper', explode(',', env('HTTP_RETRY_ALLOWED_METHODS', 'GET,HEAD,OPTIONS'))),
        'logging' => [
            'enabled' => env('HTTP_RETRY_LOGGING_ENABLED', false),
            'level' => env('HTTP_RETRY_LOGGING_LEVEL', 'info'),
            'channel' => env('HTTP_RETRY_LOGGING_CHANNEL', null),
        ],
    ],
];

License

MIT