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

Backoff Laravel Package

eventsauce/backoff

Small PHP library with a BackOffStrategy interface and ready-made retry delays (exponential, Fibonacci, linear). Configure initial delay, max tries, max delay, and growth base. Call backOff($tries, $throwable) inside retry loops to pause between attempts.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require eventsauce/backoff
    

    Ensure your project uses PHP 8.1+ (minimum requirement).

  2. First Use Case: Inject BackOffStrategy into a service handling external calls (e.g., API clients, database operations). Example:

    use EventSauce\BackOff\ExponentialBackOffStrategy;
    
    $backOff = new ExponentialBackOffStrategy(
        initialDelayMs: 100,  // 100ms initial delay
        maxTries: 3           // Max 3 retries
    );
    
  3. Where to Look First:

    • Documentation: Focus on the README for strategy examples (Exponential, Fibonacci, Linear).
    • Changelog: Check for recent features like BackOffRunner or JitterAfterThreshold if needed.

Implementation Patterns

Core Workflow

  1. Strategy Injection: Pass a configured BackOffStrategy to your service (e.g., via Laravel's Service Container or Dependency Injection).

    // Laravel Service Provider
    $this->app->bind(BackOffStrategy::class, function ($app) {
        return new ExponentialBackOffStrategy(100, 5);
    });
    
  2. Retry Loop: Use goto (or refactor to a method) to implement retries with back-off:

    public function fetchData(ApiClient $client, BackOffStrategy $backOff): void {
        $tries = 0;
        start:
        try {
            $tries++;
            $client->fetch();
        } catch (RetryableException $e) {
            if ($backOff->backOff($tries, $e)) {
                goto start;
            }
            throw $e;
        }
    }
    
  3. Laravel-Specific Patterns:

    • Jobs: Use BackOffRunner for queue jobs:
      use EventSauce\BackOff\BackOffRunner;
      
      $runner = new BackOffRunner(new ExponentialBackOffStrategy(100, 3));
      $runner->run(fn() => $this->processPayment());
      
    • Middleware: Wrap HTTP clients (e.g., Guzzle) with retry logic:
      $client = new Client([
          'handler' => HandlerStack::create([
              new RetryMiddleware($backOffStrategy),
              // Other middleware...
          ]),
      ]);
      
  4. Configuration: Centralize back-off settings in config/backoff.php:

    return [
        'strategies' => [
            'exponential' => [
                'initial_delay_ms' => 100,
                'max_tries' => 5,
                'max_delay_ms' => 2500,
                'base' => 2.0,
            ],
        ],
    ];
    

    Bind strategies dynamically in a service provider:

    $this->app->singleton(BackOffStrategy::class, function ($app) {
        return new ExponentialBackOffStrategy(
            $app['config']['backoff.strategies.exponential']
        );
    });
    

Gotchas and Tips

Pitfalls

  1. Infinite Retries:

    • Setting maxTries: -1 enables infinite retries. Avoid in production unless explicitly required (e.g., for critical systems).
    • Tip: Log retries and monitor for unexpected loops.
  2. Jitter Overuse:

    • Jitter (e.g., FullJitter) adds randomness but can increase latency unpredictably.
    • Tip: Use ScatteredJitter with a tight range (e.g., 0.1) for controlled randomness.
  3. Exception Handling:

    • backOff() returns true if retries remain; false if exhausted.
    • Gotcha: Forgetting to check the return value leads to silent failures.
    • Fix: Always verify:
      if (!$backOff->backOff($tries, $e)) {
          throw new MaxRetriesException("Failed after {$tries} attempts.");
      }
      
  4. Microseconds vs Milliseconds:

    • The library uses microseconds (e.g., 100000 = 100ms). Mistake: Passing milliseconds directly (e.g., 100) causes delays 1000x shorter.
    • Tip: Use initialDelayMs: 100 with the helper methods or multiply by 1000:
      new ExponentialBackOffStrategy(100 * 1000, 5) // 100ms initial delay
      
  5. Thread Safety:

    • Strategies are stateless and thread-safe. No issue in Laravel’s request/queue contexts.

Debugging

  1. Log Delays: Add logging to track back-off behavior:

    $backOff->backOff($tries, $e, function ($delay) {
        \Log::debug("Retrying in {$delay}µs (attempt {$tries})");
    });
    
  2. Test Edge Cases:

    • Max Delay: Verify max_delay_ms is respected (e.g., exponential growth capped at 2.5s).
    • Zero Delay: Pass initial_delay_ms: 0 for immediate retries (rarely useful).

Extension Points

  1. Custom Strategies: Implement BackOffStrategy interface:

    class CustomBackOff implements BackOffStrategy {
        public function backOff(int $tries, Throwable $throwable, ?callable $callback = null): bool {
            $delay = $tries * 1000; // Linear but with custom logic
            if ($callback) $callback($delay);
            return $tries < 5;
        }
    }
    
  2. Dynamic Jitter: Combine jitter with runtime conditions:

    $jitter = new ScatteredJitter($this->getDynamicRange());
    $backOff = new ExponentialBackOffStrategy(100, 5, jitter: $jitter);
    
  3. Laravel Events: Dispatch events on retry exhaustion:

    if (!$backOff->backOff($tries, $e)) {
        event(new MaxRetriesExceeded($e));
    }
    
  4. Prometheus Metrics: Track retries with metrics:

    $backOff->backOff($tries, $e, function ($delay) use ($metrics) {
        $metrics->inc('retries_total');
        $metrics->observe('retry_delay_ms', $delay / 1000);
    });
    
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
codifyo/ts-generator-bundle
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
christhompsontldr/laravel-inky
spatie/mailcoach-vapor