PHPackages                             mention/retry - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. mention/retry

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

mention/retry
=============

A Retry library for PHP

2.0(7mo ago)1324.5k↓20.2%MITPHPPHP &gt;=8.1

Since Nov 29Pushed 7mo ago12 watchersCompare

[ Source](https://github.com/mentionapp/retry)[ Packagist](https://packagist.org/packages/mention/retry)[ RSS](/packages/mention-retry/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (15)Versions (3)Used By (0)

Retry
=====

[](#retry)

Retry is a PHP library for retrying operations with customizable backoff, jitter, and support for both synchronous and asynchronous APIs. It also allows for offline retrying and serialization.

Features
--------

[](#features)

- Support for both synchronous and asynchronous operations
- Configurable delays: constant or exponential
- Jitter to prevent synchronization of retry attempts
- Halting on irrecoverable errors
- Offline retry capability
- Explicit serialization support

Install
-------

[](#install)

```
composer require mention/retry

```

Synchronous API
---------------

[](#synchronous-api)

```
use Mention\Retry\Retry;
use GuzzleHttp\Client;

$result = Retry::sync()->retry($operation);
```

`$operation` should be a callable, and will be called repeatedly until either:

- The function executes successfully (returns without exceptions),
- A PermanentError is thrown indicating a retry would have the same outcome,
- The RetryStrategy halted the retrying process after a certain number of retries or elapsed time

On success, `Retry::sync()->retry($operation)` returns the value of `$operation()`.

The following example will retry until `$client->get('http://example.com/')` is successful, or 1 minute has elasped (as per the default RetryStrategy) :

```
use Mention\Retry\Retry;
use GuzzleHttp\Client;

$response = Retry::sync()->retry(function() {
    $client = new Guzzlehttp\Client();
    return $client->get('http://example.com/');
});
```

Asynchronous API
----------------

[](#asynchronous-api)

The async API works similarly, but expects the operation to return a `React\PromiseInterface`:

```
use Mention\Retry\Retry;

Retry::async($loop)->retry(function() {
    $browser = new React\Http\Browser();
    return $browser->get('http://example.com/');
});
```

Permanent errors
----------------

[](#permanent-errors)

Sometimes it can be determined that retrying will not work. For example, it is unlikely that retrying after receiving an HTTP 4xx error will change the outcome.

In these cases the operation can halt the retry process by throwing a `Mention\Retry\PermanentError`. When this exceptions is thrown, `retry()` stops retrying and re-throws either the inner exception if any, or the PermanentError itself.

Example:

```
use Mention\Retry\Retry;
use Mention\Retry\PermanentError;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;

$response = Retry::sync()->retry(function() {
    $client = new Guzzlehttp\Client();
    try {
        return $client->get('http://example.com/404');
    } catch (ClientException $e) {
        throw PermanentError::withException($e);
    }
});
```

RetryStrategy
-------------

[](#retrystrategy)

Both `Retry::sync()` and `Retry::async()` accept a `RetryStrategy` argument that can be used to configure the retry behavior.

```
use Mention\Retry\RetryStrategy\RetryStrategyBuilder;
use Mention\Kebab\Duration\Duration;

$strategy = RetryStrategyBuilder::exponentialInteractive()->withMaxElapsedTime(Duration::seconds(15));
$response = Retry::sync($strategy)->retry($operation);
```

### Default strategy

[](#default-strategy)

When no `RetryStrategy` is passed, a default strategy is used. It is configured as follows:

- The delay is exponential, starts at 10 milliseconds and increases by a factor of 1.5 after each attempt
- A jitter of 0.5 is applied to the delay to help prevent operations from synchronising with each other and sending surges of requests
- Retrying halts after 60 seconds have elasped without success

It is possible to change the default strategy by calling `Mention\Retry::setDefaultRetryStrategy()`:

```
use Mention\Retry\RetryStrategy\RetryStrategyBuilder;
use Mention\Kebab\Duration\Duration;

$defaultStrategy = RetryStrategyBuilder::exponentialInteractive()->withMaxElapsedTime(Duration::seconds(15));
Retry::setDefaultRetryStrategy($defaultStrategy);
```

It can be useful to set a different default retry strategy in different contexts. For example, code executing in a web context should retry for a shorter time than code executing in a batch context. Changing the default retry strategy can be used for exactly that.

In tests it can be useful to ignore the default and custom strategies. This can be done by calling `Mention\Retry::overrideRetryStrategy()`:

```
use Mention\Retry\RetryStrategy\RetryStrategyBuilder;

$testStrategy = RetryStrategyBuilder::noDelay();
Retry::overrideRetryStrategy($defaultStrategy);
```

Use of `Retry::overrideRetryStrategy()` outside of tests is discouraged. Use `Retry::setDefaultRetryStrategy()` instead, or pass an explicit strategy when calling `Retry::sync()` and `Retry::async()`.

### Custom strategies

[](#custom-strategies)

The `Mention\Retry\RetryStrategy\RetryStrategyBuilder` class allows you to build custom strategies and to customize the following parameters:

- The delay between two attempts
- How much jitter should be applied to the delay
- The maximum number of attempts
- The maximum amount of elapsed time

The builder provides a number of predefine strategies that can be further customized. See .

### Serialization

[](#serialization)

Retry strategies can be serialized by calling the `->toJsonString()` method and deserialized by calling `::fromJsonString()`. This is designed to be persisted for later usage, and future versions of the library will support strategies serialized with previous versions.

Offline retrying
----------------

[](#offline-retrying)

`RetryStrategy` is stateless and can be used standalone to implement offline retrying. For example, it can be used in a scheduled task system in order to decide if and when to re-schedule a failing task:

```
try {
    $task->execute();
} catch (\Exception $e) {
    $task->increaseFailures();
    $retryStrategy = $task->getRetryStrategy();
    if (!$retryStrategy->shouldRetry($task->getFailuesCount(), $task->getOriginalScheduleTime())) {
        throw $e;
    } else {
        $delay = $retryStrategy->getDelay($task->getFailuesCount());
        $task->rescheduleWithDelay($delay);
    }
}
```

###  Health Score

43

—

FairBetter than 91% of packages

Maintenance62

Regular maintenance activity

Popularity34

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 83.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~665 days

Total

2

Last Release

235d ago

Major Versions

1.0 → 2.02025-09-25

### Community

Maintainers

![](https://www.gravatar.com/avatar/7fccf26146a280cb4069b86f23fe91eeb3fbae987f25fd328606995080c0379f?d=identicon)[arnaud-lb](/maintainers/arnaud-lb)

---

Top Contributors

[![arnaud-lb](https://avatars.githubusercontent.com/u/365207?v=4)](https://github.com/arnaud-lb "arnaud-lb (5 commits)")[![Florian-agora](https://avatars.githubusercontent.com/u/216533187?v=4)](https://github.com/Florian-agora "Florian-agora (1 commits)")

---

Tags

phpretryretrying

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/mention-retry/health.svg)

```
[![Health](https://phpackages.com/badges/mention-retry/health.svg)](https://phpackages.com/packages/mention-retry)
```

###  Alternatives

[react/react

ReactPHP: Event-driven, non-blocking I/O with PHP.

9.1k3.6M63](/packages/react-react)[internal/dload

Downloads binaries.

98142.7k10](/packages/internal-dload)[wyrihaximus/react-child-process-messenger

Messenger decorator for react/child-process

32279.4k4](/packages/wyrihaximus-react-child-process-messenger)[wyrihaximus/react-cron

⏱️ Cronlike scheduler running inside the ReactPHP Event Loop

4050.6k](/packages/wyrihaximus-react-cron)[llm/mcp-server

PHP SDK for building MCP servers

431.1k](/packages/llm-mcp-server)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
