netlogix/retry

Retries a specific PHP code fragment.

Maintainers

Package info

github.com/netlogix/retry

pkg:composer/netlogix/retry

Transparency log

Statistics

Installs: 133 768

Dependents: 1

Suggesters: 0

Stars: 1

Open Issues: 0

1.1.0 2026-07-03 15:49 UTC

This package is auto-updated.

Last update: 2026-07-03 15:50:31 UTC


README

Retries a specific PHP code fragment (called a "task") as long as the "when" condition evaluates to true.

(new \Netlogix\Retry\Retry())
    ->when(condition: fn(int $incarnation) => $incarnation < PHP_INT_MAX)
    ->task(subject: fn () => throw new \RuntimeException('false'));

There is a shorthand method for counting retries and sleeping between attempts with increasing intervals.

(new \Netlogix\Retry\Retry())
    /**
     * http://backoffcalculator.com/?attempts=5&rate=1&interval=0.5
     * = (0.5 + 1 + 1.5 + 2.0 + 2.5) seconds
     * = 7.5 seconds
     */
    ->withExponentialBackoff(retryInterval: 0.5, maxRetries: 5)
    ->onExceptionsOfType(\Doctrine\DBAL\Exception\DeadlockException::class)
    ->task(fn () => $dbal->executeQuery($statement));

Reacting to errors

The onError handler is invoked for every caught throwable, even for those the retry does not react to. It receives the throwable, a flag telling whether the throwable is one of the configured types to retry on, and the current incarnation (retry count). This is the place to forward exceptions to a logger or, for example, the Neos/Flow ThrowableStorageInterface.

(new \Netlogix\Retry\Retry())
    ->withExponentialBackoff(retryInterval: 0.5, maxRetries: 5)
    ->onExceptionsOfType(\Doctrine\DBAL\Exception\DeadlockException::class)
    ->onError(function (\Throwable $throwable, bool $shouldConsider, int $incarnation) use ($throwableStorage) {
        $throwableStorage->logThrowable($throwable);
    })
    ->task(fn () => $dbal->executeQuery($statement));

Returning false from the onError handler aborts retrying immediately and rethrows the throwable — the same "throw through" behaviour as an exhausted retry limit or a throwable of a type the retry does not react to. Returning anything else (including nothing) lets the normal retry logic proceed.

->onError(function (\Throwable $throwable) use ($throwableStorage) {
    $throwableStorage->logThrowable($throwable);

    if ($throwable instanceof \Some\Fatal\Exception) {
        return false; // stop retrying, rethrow immediately
    }
})