stechstudio / backoff
PHP 库,提供多种回退策略和抖动支持的重试功能
Requires (Dev)
- phpunit/phpunit: ^10.0
README
轻松使用重试功能封装您的代码。此库提供
- 4 种回退策略(以及使用您自己的能力)
- 可选的抖动/随机性以分散重试并最小化碰撞
- 等待时间上限
- 用于自定义重试逻辑或错误处理的回调
安装
composer require stechstudio/backoff
默认值
此库提供合理的默认值,因此您可以在大多数用例中直接使用。
默认情况下,回退是二次的,基础时间为 100 毫秒(attempt^2 * 100
),最大重试次数为 5,没有抖动。
快速入门
使用 Backoff 的最简单方法是使用全局 backoff
辅助函数
$result = backoff(function() { return doSomeWorkThatMightFail(); });
如果成功,$result
将包含闭包的结果。如果超过最大尝试次数,则内部异常将被重新抛出。
当然,如果需要,您可以通过辅助方法提供其他选项。
方法参数是 $callback
、$maxAttempts
、$strategy
、$waitCap
、$useJitter
。
Backoff 类使用
Backoff 类构造函数参数是 $maxAttempts
、$strategy
、$waitCap
、$useJitter
。
$backoff = new Backoff(10, 'exponential', 10000, true); $result = $backoff->run(function() { return doSomeWorkThatMightFail(); });
如果您通过依赖注入容器注入 Backoff 类,则可以在之后设置它。请注意,设置器是可链接的。
// Assuming a fresh instance of $backoff was handed to you $result = $backoff ->setStrategy('constant') ->setMaxAttempts(10) ->enableJitter() ->run(function() { return doSomeWorkThatMightFail(); });
更改默认值
如果您想使用不同的默认值,可以通过静态类属性进行修改
Backoff::$defaultMaxAttempts = 10; Backoff::$defaultStrategy = 'exponential'; Backoff::$defaultJitterEnabled = true;
例如,您可以在应用程序引导过程中进行此操作。这些默认值将在您创建 Backoff 类实例或使用 backoff()
辅助函数时使用。
策略
有四个内置策略可供使用:常数、线性、多项式和指数。
所有策略的默认基础时间都是 100 毫秒。
常数
$strategy = new ConstantStrategy(500);
此策略将在每次重试循环中暂停 500 毫秒。
线性
$strategy = new LinearStrategy(200);
此策略将在 attempt * baseTime
暂停,提供从 200 毫秒开始的线性回退。
多项式
$strategy = new PolynomialStrategy(100, 3);
此策略将在 (attempt^degree) * baseTime
暂停,因此在这种情况下 (attempt^3) * 100
。
如果没有提供度数,则默认值为 2,实际上是二次时间。
指数
$strategy = new ExponentialStrategy(100);
此策略将在 (2^attempt) * baseTime
暂停。
指定策略
在我们之前的代码示例中,我们将策略指定为字符串
backoff(function() { ... }, 10, 'constant'); // OR $backoff = new Backoff(10, 'constant');
这将使用具有默认值的 ConstantStrategy
,实际上为您提供 100 毫秒的暂停时间。
您可以自己创建策略实例以修改这些默认值
backoff(function() { ... }, 10, new LinearStrategy(500)); // OR $backoff = new Backoff(10, new LinearStrategy(500));
您还可以将整数作为策略传递,它将转换为以毫秒为单位的基准时间的 ConstantStrategy
backoff(function() { ... }, 10, 1000); // OR $backoff = new Backoff(10, 1000);
最后,如果您愿意,可以将闭包作为策略传递。此闭包应接收整数 attempt
并返回以毫秒为单位的暂停时间。
backoff(function() { ... }, 10, function($attempt) { return (100 * $attempt) + 5000; }); // OR $backoff = new Backoff(10); $backoff->setStrategy(function($attempt) { return (100 * $attempt) + 5000; });
等待时间上限
如果您想使用快速增长的回退时间(如指数),但随后也设置最大等待时间,以便过一段时间后水平化。
此上限可以作为 backoff
辅助函数的第四个参数提供,或使用 Backoff 类上的 setWaitCap()
方法。
抖动
如果您有很多客户端同时开始一个作业并遇到故障,上述任何回退策略都可能导致工人在每次重试时继续发生碰撞。
解决这个问题可以通过添加随机性来实现。请参见这里以获得良好的解释
https://www.awsarchitectureblog.com/2015/03/backoff.html
您可以通过将true
作为第五个参数传递给backoff
辅助函数,或者使用Backoff类的enableJitter()
方法来启用抖动。
我们使用上述文章中概述的“FullJitter”方法,该方法使用介于0和您所选策略提供的睡眠时间之间的随机数。
自定义重试决策器
默认情况下,如果遇到异常且尚未达到最大重试次数,Backoff将进行重试。
您可能需要为更高级的使用场景提供自己的重试决策器。也许您想根据时间而不是重试次数来重试,或者可能存在即使在未遇到异常的情况下也想重试的场景。
将决策器作为回调提供,或者提供一个具有__invoke
方法的类的实例。Backoff将提供四个参数:当前尝试次数、最大尝试次数、收到的最后一个结果以及如果遇到异常则提供的异常。您的决策器需要返回true或false。
$backoff->setDecider(function($attempt, $maxAttempts, $result, $exception = null) { return someCustomLogic(); });
错误处理回调
您可以提供自定义错误处理程序以在发生异常时通知,即使我们尚未达到最大尝试次数。例如,这是一个进行日志记录的有用位置。
$backoff->setErrorHandler(function($exception, $attempt, $maxAttempts) { Log::error("On run $attempt we hit a problem: " . $exception->getMessage()); });