jbzoo/retry

提供多种回退策略和抖动支持的轻量级PHP重试功能库

7.0.1 2024-01-28 11:14 UTC

This package is auto-updated.

Last update: 2024-08-28 12:31:10 UTC


README

CI Coverage Status Psalm Coverage Psalm Level CodeFactor
Stable Version Total Downloads Dependents GitHub License

  1. 4种重试策略(以及使用您自己的能力)
  2. 可选的抖动/随机性,以分散重试并最小化冲突
  3. 等待时间上限
  4. 自定义重试逻辑或错误处理的回调

备注

  • 这是一个分支。您可以在这里找到原始项目。
  • 现在代码库非常严格,尽可能多地覆盖了测试。原始作者非常棒,但代码有点糟糕 :) 这太简单了,只花了我一个晚上... ;)
  • 我不喜欢在代码中使用“回退”这个词。是的,很有趣,但...我相信“重试”更明显。抱歉 :)
  • 使用导入代替全局命名空间中的函数没有问题。不要使用过时的做法。
  • 具有默认值的静态变量已弃用并禁用。请参阅以下思考。
  • 新方法 setJitterPercent|getJitterPercentsetJitterMinCap|getJitterMinCap 进行精细调整。
  • 我的项目有别名,以与原始项目保持向后兼容。 ;)

安装

composer require jbzoo/retry

默认设置

此库提供合理的默认设置,因此您可以在大多数用例中直接使用。

默认情况下,重试是二次的,基本时间为100毫秒(attempt^2 * 100),最大重试次数为5次,没有抖动。

快速入门

使用Retry的最简单方法是使用retry辅助函数

use function JBZoo\Retry\retry;

$result = retry(function() {
    return doSomeWorkThatMightFail();
});

如果成功,则$result将包含闭包的结果。如果超出最大尝试次数,则内部异常将重新抛出。

当然,如果需要,您可以通过辅助方法提供其他选项。

方法参数是$callback$maxAttempts$strategy$waitCap$useJitter

Retry类使用

Retry类构造函数参数为$maxAttempts$strategy$waitCap$useJitter

use JBZoo\Retry\Retry;

$retry = new Retry(10, 'exponential', 10000, true);
$result = $retry->run(function() {
    return doSomeWorkThatMightFail();
});

或者如果您使用依赖注入容器注入Retry类,您可以在之后设置它。请注意,设置器是可链接的。

use JBZoo\Retry\Retry;

// Assuming a fresh instance of $retry was handed to you
$result = (new Retry())
    ->setStrategy('constant')
    ->setMaxAttempts(10)
    ->enableJitter()
    ->run(function() {
        return doSomeWorkThatMightFail();
    });

更改默认设置

重要提示:这是一个分支。所以我只是保留它以保持向后兼容。静态变量已弃用且根本不工作!

这是可怕的实践!明确优于隐式。 ;)

  • 示例 #1. 您的项目不同部分可以有不同的设置。
  • 示例 #2. 想象一下,如果某个第三方库(在./vendor中)使用了它自己的默认设置会发生什么。让我们战斗!
  • 示例 #3. 这只是一个尝试将变量存储在全局命名空间中的尝试。你看出来了吗?

因此,下一个变量已弃用,并且它们不影响任何内容。

use JBZoo\Retry\Retry;

Retry::$defaultMaxAttempts;
Retry::$defaultStrategy;
Retry::$defaultJitterEnabled;

只需使用依赖注入等方法,不要浪费你的精力。

策略

有四种内置策略可供使用:常数、线性、多项式和指数。

所有策略的基本时间默认为100毫秒。

常数

use JBZoo\Retry\Strategies\ConstantStrategy;

$strategy = new ConstantStrategy(500);

此策略将在每次重试循环中暂停500毫秒。

线性

use JBZoo\Retry\Strategies\LinearStrategy;
$strategy = new LinearStrategy(200);

此策略将暂停为attempt * baseTime,提供从200毫秒开始的线性重试。

多项式

use JBZoo\Retry\Strategies\PolynomialStrategy;
$strategy = new PolynomialStrategy(100, 3);

此策略将暂停为(attempt^degree) * baseTime,因此在这种情况下为(attempt^3) * 100

如果没有提供,默认程度为2,实际上是二次时间复杂度。

指数型

use JBZoo\Retry\Strategies\ExponentialStrategy;
$strategy = new ExponentialStrategy(100);

此策略将睡眠时间为 (2^attempt) * baseTime

指定策略

在我们之前的代码示例中,我们指定策略为一个字符串

use JBZoo\Retry\Retry;
use function JBZoo\Retry\retry;

retry(function() {
    // ...
}, 10, 'constant');

// OR

$retry = new Retry(10, 'constant');

这会使用默认值的 ConstantStrategy,实际上提供了100毫秒的睡眠时间。

您可以通过创建策略实例来修改这些默认值

use JBZoo\Retry\Retry;
use JBZoo\Retry\Strategies\LinearStrategy;
use function JBZoo\Retry\retry;

retry(function() {
    // ...
}, 10, new LinearStrategy(500));

// OR

$retry = new Retry(10, new LinearStrategy(500));

您也可以传入一个整数作为策略,将其转换为以毫秒为基时间的 ConstantStrategy

use JBZoo\Retry\Retry;
use function JBZoo\Retry\retry;

retry(function() {
    // ...
}, 10, 1000);

// OR

$retry = new Retry(10, 1000);

最后,如果您愿意,可以将闭包作为策略传入。此闭包应接收一个整数 attempt 并返回一个以毫秒为单位的睡眠时间。

use JBZoo\Retry\Retry;
use function JBZoo\Retry\retry;

retry(function() {
    // ...
}, 10, function($attempt) {
    return (100 * $attempt) + 5000;
});

// OR

$retry = new Retry(10);
$retry->setStrategy(function($attempt) {
    return (100 * $attempt) + 5000;
});

等待上限

您可能希望使用快速增长的重试时间(如指数型),但同时设置最大等待时间,以便在一段时间后趋于平稳。

此上限可以作为 retry 辅助函数的第四个参数提供,或使用 Retry 类的 setWaitCap() 方法。

抖动

如果您有很多客户端同时开始一个作业并遇到失败,上述任何重试策略都可能导致工人在每次重试时继续碰撞。

解决方案是添加随机性。请参见此处以获取良好的解释

https://aws.amazon.com/ru/blogs/architecture/exponential-backoff-and-jitter

您可以通过将 true 作为 retry 辅助函数的第五个参数传入或使用 Retry 类上的 enableJitter() 方法来启用抖动。

默认情况下,我们使用上述文章中概述的 "FullJitter" 方法,其中使用介于0和所选策略提供的睡眠时间之间的随机数。

但您可以使用 setJitterPercent(). 方法更改抖动的最大时间,默认值为100。您还可以使用 setJitterMinCap 设置抖动的最小值(默认为0)。

自定义重试决策者

默认情况下,Retry 遇到异常时会重试,并且尚未达到最大重试次数。

您可能需要提供自己的决策者以用于更复杂的情况。也许您希望根据时间而不是重试次数来重试,或者也许有场景在未遇到异常的情况下您也想要重试。

提供回调或具有 __invoke 方法的类的实例作为决策者。Retry 将传递四个参数:当前尝试次数、最大尝试次数、收到的最后一个结果以及遇到的异常(如果有)。您的决策者需要返回 true 或 false。

use JBZoo\Retry\Retry;

$retry = new Retry();
$retry->setDecider(function($attempt, $maxAttempts, $result, $exception = null) {
    return someCustomLogic();
});

错误处理回调

您可以提供一个自定义的错误处理程序,以便在发生异常时被通知,即使我们尚未达到最大尝试次数。这是一个进行日志记录的有用地方。

use JBZoo\Retry\Retry;

$retry = new Retry();
$retry->setErrorHandler(function($exception, $attempt, $maxAttempts) {
    Log::error("On run {$attempt}/{$maxAttempts} we hit a problem: {$exception->getMessage()}");
});

单元测试和检查代码风格

make update
make test-all

许可证

MIT

另请参阅

  • CI-Report-Converter - 转换不同的错误报告,以便与流行的 CI 系统实现深度兼容。
  • Composer-Diff - 查看 composer update 后更改了哪些包。
  • Composer-Graph - 基于 mermaid-js 的 composer.json 的依赖关系图可视化。
  • Mermaid-PHP - 使用 mermaid 脚本语言生成图表和流程图。
  • Utils - 收集有用的 PHP 函数、迷你类和日常片段。
  • Image - 该软件包提供了一种面向对象的方式来尽可能简单地操作图像。
  • Data - 扩展了ArrayObject的实现。使用文件作为配置/数组。
  • SimpleTypes - 转换任何值和度量 - 货币、重量、汇率、长度、...