PHP code example of crowdstar / exponential-backoff

1. Go to this page and download the library: Download crowdstar/exponential-backoff library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

crowdstar / exponential-backoff example snippets



use CrowdStar\Backoff\EmptyValueCondition;
use CrowdStar\Backoff\ExponentialBackoff;

$result = (new ExponentialBackoff(new EmptyValueCondition()))->run(
    function () {
        return MyClass::fetchData();
    }
);


use CrowdStar\Backoff\ExceptionBasedCondition;
use CrowdStar\Backoff\ExponentialBackoff;

// Allow to catch multiple types of exceptions.
$backoff = new ExponentialBackoff(new ExceptionBasedCondition(LogicException::class, RuntimeException::class));
try {
    $result = $backoff->run(
        function () {
            return MyClass::fetchData();
        }
    );
} catch (Throwable $t) {
    // Handle the errors here.
}


use CrowdStar\Backoff\ExceptionBasedCondition;
use CrowdStar\Backoff\ExponentialBackoff;

// Retry any HttpException -- a 503 or a timeout is worth another attempt -- but give up on a 400 right away, since
// sending the same bad request again will fail the same way.
$condition = (new ExceptionBasedCondition(HttpException::class))
    ->setIgnoredExceptions(HttpBadRequestException::class);

$result = (new ExponentialBackoff($condition))->run(
    function () {
        return MyClass::fetchData();
    }
);


use CrowdStar\Backoff\AbstractRetryCondition;
use CrowdStar\Backoff\ExponentialBackoff;

$backoff = new ExponentialBackoff(
    new class extends AbstractRetryCondition {
        public function throwable(): bool
        {
            return false;
        }
        public function shouldRetry(mixed $result, ?Exception $e): bool
        {
            return ($e instanceof Exception);
        }
    }
);

$backoff->run(
    function () {
        return MyClass::fetchData();
    }
);


use CrowdStar\Backoff\ExponentialBackoff;

$result = ExponentialBackoff::when(fn (mixed $result): bool => empty($result))->run(
    function () {
        return MyClass::fetchData();
    }
);


use CrowdStar\Backoff\ExponentialBackoff;

// Retry when a \RuntimeException was thrown, and don't throw it out when the last attempt still fails.
$backoff = ExponentialBackoff::when(
    fn (mixed $result, ?Exception $e): bool => ($e instanceof RuntimeException),
    false
);
$result = $backoff->run(
    function () {
        return MyClass::fetchData();
    }
);


use CrowdStar\Backoff\AbstractRetryCondition;
use CrowdStar\Backoff\ExponentialBackoff;

final class UntilRateLimitLifts extends AbstractRetryCondition
{
    public function shouldRetry(mixed $result, ?Exception $e): bool
    {
        return ($result?->getStatusCode() === 429);
    }
}

$result = (new ExponentialBackoff(new UntilRateLimitLifts()))->run(
    function () {
        return MyClass::fetchData();
    }
);


use CrowdStar\Backoff\EmptyValueCondition;
use CrowdStar\Backoff\ExceptionBasedCondition;
use CrowdStar\Backoff\ExponentialBackoff;
use CrowdStar\Backoff\Jitter;

$backoff = new ExponentialBackoff(new EmptyValueCondition());
$backoff = new ExponentialBackoff(new ExceptionBasedCondition());
$backoff = new ExponentialBackoff(new ExceptionBasedCondition(LogicException::class, RuntimeException::class));
$backoff = ExponentialBackoff::when(fn (mixed $result, ?Exception $e): bool => ($e instanceof Exception));

$backoff
    ->setInitialDelay(1_000_000)  // Wait up to about 1 second before the first retry; jitter decides.
    ->setInitialDelay(ExponentialBackoff::DEFAULT_INITIAL_DELAY)
    ->setMaxAttempts(3)
    ->setMaxAttempts(4)
    ->setMaxDelay(5_000_000)  // Wait at most 5 seconds between two attempts.
    ->setMaxDelay(ExponentialBackoff::DEFAULT_MAX_DELAY)
    ->setMaxElapsedTime(2_000_000)  // Give the whole run 2 seconds, however many attempts fit inside it.
    ->setMaxElapsedTime(null)       // No budget at all. The default.
    ->setJitter(Jitter::Equal)  // Wait at least half of the calculated delay, and randomly up to all of it.
    ->setJitter(Jitter::None)   // Wait exactly as long as calculated; predictable, but no protection from collisions.
    ->setJitter(Jitter::Full);  // Wait anywhere between nothing and the calculated delay. The default.

$result = $backoff->run(
    function () {
        return MyClass::fetchData();
    }
);


use CrowdStar\Backoff\EmptyValueCondition;
use CrowdStar\Backoff\ExponentialBackoff;
use CrowdStar\Backoff\Mode;

// Never wait with Swoole's coroutine sleep, even inside a coroutine.
$backoff = new ExponentialBackoff(new EmptyValueCondition(), Mode::Blocking);

// Wait non-blockingly wherever a coroutine is running -- which is what happens anyway, so this is the same as
// passing nothing at all.
$backoff = new ExponentialBackoff(new EmptyValueCondition(), Mode::Swoole);

$backoff->getMode();  // Mode::Swoole or Mode::Blocking, whichever the next wait would use.


use CrowdStar\Backoff\EmptyValueCondition;
use CrowdStar\Backoff\ExponentialBackoff;
use CrowdStar\Backoff\Jitter;

$slept   = [];
$backoff = (new ExponentialBackoff(new EmptyValueCondition()))
    ->setJitter(Jitter::None)
    ->setSleeper(function (int $microSeconds) use (&$slept): void {
        $slept[] = $microSeconds;
    });

$backoff->run(function () { return MyClass::fetchData(); });

// $slept is now [250000, 500000, 1000000], and the test took no time at all.


$result = MyClass::fetchData();


use CrowdStar\Backoff\EmptyValueCondition;
use CrowdStar\Backoff\ExponentialBackoff;

$backoff = new ExponentialBackoff(new EmptyValueCondition());
$backoff->disable();
$result = $backoff->run(function () {return MyClass::fetchData();});


use CrowdStar\Backoff\ExponentialBackoff;
use CrowdStar\Backoff\NullCondition;

$result = (new ExponentialBackoff(new NullCondition()))
    ->setRetryCondition(new NullCondition()) // The method here is for demonstration purpose.
    ->run(function () {return MyClass::fetchData();});