crowdstar/exponential-backoff

通过每次迭代将超时时间加倍来防止过载不可用的服务。

3.0.11 2023-05-05 22:27 UTC

This package is auto-updated.

Last update: 2024-09-19 05:50:22 UTC


README

Library Status Latest Stable Version Latest Unstable Version License

摘要

指数退避通过每次迭代将超时时间加倍来防止过载不可用的服务。此类使用指数退避算法来计算下一次请求的超时时间。

此库允许在 Swoole 中以非阻塞模式进行指数退避。

安装

composer require crowdstar/exponential-backoff:~3.0.0

示例用法

在以下代码片段中,我们假设您希望将方法 MyClass::fetchData() 的返回值存储在变量 $result 中,并且您要对它进行指数退避,因为当运行方法 MyClass::fetchData() 时可能会发生意外。

1. 当返回值为空时重试

以下代码尝试使用方法 MyClass::fetchData() 获取一些非空数据。此代码段将尝试多次(默认为4次)直到我们获取一些非空数据,或者达到最大重试次数。

<?php
use CrowdStar\Backoff\EmptyValueCondition;
use CrowdStar\Backoff\ExponentialBackoff;

$result = (new ExponentialBackoff(new EmptyValueCondition()))->run(
    function () {
        return MyClass::fetchData();
    }
);
?>

2. 当抛出特定异常时重试

以下代码尝试使用方法 MyClass::fetchData() 获取一些数据,该方法可能会抛出异常。此代码段将尝试多次(默认为4次)直到我们获取一些数据,或者达到最大重试次数。

注意:内部 PHP 错误(类 Error)不会触发指数退避。它们应该手动修复。

<?php
use CrowdStar\Backoff\ExceptionBasedCondition;
use CrowdStar\Backoff\ExponentialBackoff;

// Allow to catch multiple types of exceptions and throwable objects.
$backoff = new ExponentialBackoff(new ExceptionBasedCondition(Exception::class, Throwable::class));
try {
    $result = $backoff->run(
        function () {
            return MyClass::fetchData();
        }
    );
} catch (Throwable $t) {
    // Handle the errors here.
}
?>

当最终失败时不要抛出异常

当方法调用 MyClass::fetchData() 最终失败并捕获异常时,我们可以通过重写方法 AbstractRetryCondition::throwable() 来静默异常而无需抛出它。

<?php
use CrowdStar\Backoff\AbstractRetryCondition;
use CrowdStar\Backoff\ExponentialBackoff;

$backoff = new ExponentialBackoff(
    new class extends AbstractRetryCondition {
        public function throwable(): bool
        {
            return false;
        }
        public function met($result, ?Exception $e): bool
        {
            return (empty($e) || (!($e instanceof Exception)));
        }
    }
);

$backoff->run(
    function () {
        return MyClass::fetchData();
    }
);
?>

如果需要,您可以在重写方法 AbstractRetryCondition::throwable() 时定义更复杂的逻辑。

3. 当满足自定义条件时重试

以下代码尝试使用方法 MyClass::fetchData() 获取一些非空数据。此代码段与第一个示例相同,不同之处在于这里使用了一个自定义条件类,而不是类 \CrowdStar\Backoff\EmptyValueCondition

<?php
use CrowdStar\Backoff\AbstractRetryCondition;
use CrowdStar\Backoff\ExponentialBackoff;

$backoff = new ExponentialBackoff(
    new class extends AbstractRetryCondition {
        public function met($result, ?Exception $e): bool
        {
            return !empty($result);
        }
    }
);
$result = $backoff->run(
    function () {
        return MyClass::fetchData();
    }
);
?>

4. 进行指数退避时更多选项

以下代码尝试使用方法 MyClass::fetchData() 获取一些数据。此代码段与第二个示例相同,不同之处在于这里使用了一个自定义条件类,而不是类 \CrowdStar\Backoff\ExceptionBasedCondition

在此代码段中,我们还展示了使用此包进行指数退避时有哪些选项可用。

<?php
use CrowdStar\Backoff\AbstractRetryCondition;
use CrowdStar\Backoff\EmptyValueCondition;
use CrowdStar\Backoff\ExceptionBasedCondition;
use CrowdStar\Backoff\ExponentialBackoff;

$backoff = new ExponentialBackoff(new EmptyValueCondition());
$backoff = new ExponentialBackoff(new ExceptionBasedCondition());
$backoff = new ExponentialBackoff(new ExceptionBasedCondition(Exception::class, Throwable::class));
$backoff = new ExponentialBackoff(
    new class extends AbstractRetryCondition {
        public function met($result, ?Exception $e): bool
        {
            return (empty($e) || (!($e instanceof Exception)));
        }
    }
);

$backoff
    ->setType(ExponentialBackoff::TYPE_SECONDS)
    ->setType(ExponentialBackoff::TYPE_MICROSECONDS)
    ->setMaxAttempts(3)
    ->setMaxAttempts(4);

$result = $backoff->run(
    function () {
        return MyClass::fetchData();
    }
);
?>

5. 临时禁用指数退避

有两种方法可以暂时禁用以下代码段的指数退避:

<?php
$result = MyClass::fetchData();
?>

首先,您可以通过调用方法 \CrowdStar\Backoff\ExponentialBackoff::disable() 暂时禁用指数退避。例如

<?php
use CrowdStar\Backoff\EmptyValueCondition;
use CrowdStar\Backoff\ExponentialBackoff;

$backoff = new ExponentialBackoff(new EmptyValueCondition());
$backoff->disable();
$result = $backoff->run(function () {return MyClass::fetchData();});
?>

您还可以使用类 \CrowdStar\Backoff\NullCondition 临时禁用指数退避

<?php
use CrowdStar\Backoff\ExponentialBackoff;
use CrowdStar\Backoff\NullCondition;

$result = (new ExponentialBackoff(new NullCondition()))
    ->setRetryCondition(new NullCondition()) // The method here is for demonstration purpose.
    ->run(function () {return MyClass::fetchData();});
?>

这三个代码片段都一样,方法调用 MyClass::fetchData() 的返回值赋给变量 $result

示例脚本

示例脚本可以在 examples/ 文件夹中找到。在 CLI 下运行它们之前,请首先运行 composer update。

composer update -n