enl/retry-loop

Retry Loop 是一个用于广泛使用在失败代码重试概念的微型类

1.0.0 2017-09-29 14:40 UTC

This package is auto-updated.

Last update: 2024-08-29 04:37:12 UTC


README

Retry Loop 是一个广泛使用且容易解释的概念,可以用“失败重试并在多次重试后放弃”来描述。

安装

composer require enl/retry-loop

用法

例如,我们需要将一些数据推送到远程服务,以下是一个伪代码示例

$response = $serviceClient->push($uri, $data);

但假设这个远程服务暂时不可用,或者在这个特定时刻网络连接不稳定呢?

常见的解决方案是使用 try-catch。但多次重试怎么办?

这段代码看起来更好,而且效果也不错

$loop = new RetryLoop($retries = 5);
$response = $loop->run(function() use ($serviceClient, $uri, $data) {
    return $serviceClient->push($uri, $data);
});

放弃某些异常

有时,你需要放弃某些异常,例如,如果你的客户端抛出 'BadRequestException',你应该放弃尝试推送数据。为了实现这一点,你可以在 RetryLoop 构造函数中指定第二个参数

$loop = new RetryLoop($retries = 5, $giveUpAt = [BadRequestException::class]);
$response = $loop->run(function() use ($serviceClient, $uri, $data) {
    return $serviceClient->push($uri, $data);
});

在遇到 BadRequestException 时,RetryLoop 将抛出 LoopFailed 异常,并将实际异常作为前一个异常

重试前的钩子

如果你需要在重试之前执行某些操作(日志记录、重新连接等),只需使用 $beforeRetry 参数

$loop = new RetryLoop($retries = 5, $giveUpAt = [BadRequestException::class], function($e) {
    $this->log('info', 'Exception caught by retry loop, retrying: '.$e->getMessage());
});
$response = $loop->run(function() use ($serviceClient, $uri, $data) {
    return $serviceClient->push($uri, $data);
});

RetryLoop 是不可变的!

RetryLoop 类本身是不可变的,不存储任何内部状态,除了构造函数提供的参数,因此你可以轻松地重用单个循环实例进行多次重试,如果需要的话

构建器

此外,还有一个 LoopBuilder,它提供循环构建的流畅接口

$loop = RetryLoop::builder
    ->retries(5)
    ->giveUpAt(BadRequestException::class)
    ->giveUpAt(SomeOtherException::class)
    ->giveUpAt([YetAnotherException::class])
    ->beforeRetry(function() { sleep(5); })
    ->get(); // or just `run` and get result if builder is not needed after that.