ctroms / retryable
轻松确定并重试失败请求,具有可配置的策略
Requires
- php: ^7.2.5|^8.0
- laravel/framework: ^7.0|^8.0|^9.0|^10.0
Requires (Dev)
- orchestra/testbench: ^5.0|^6.0|^7.0|^8.0
README
Retryable 是一个为 Laravel 框架构建的包,它使得重试失败的请求变得轻而易举。
安装
composer install ctroms/retryable
使用
默认策略
开始的最快方式是简单地将您的请求逻辑的可调用对象传递给 retry()
。默认情况下,这使用0到1000毫秒之间的恒定抖动和最大延迟64秒的指数退避。只需传递一个包含您的重试逻辑的可调用对象作为参数。
$response = Retry::retry(function () { return $this->client->request('GET', $url, $params); });
流畅策略构建器
Retry
对象公开了一个流畅的接口,可以轻松构建您的可重试请求的策略。
$response = Retry::errors(422) ->times(10) ->maxDelay(64000) ->base(1000) ->jitter(JitterStrategy::CONSTANT) ->backoff(BackoffStrategy::EXPONENTIAL) ->retry(function () { return $this->client->request('GET', $url, $params); });
重试特定错误
要指定可重试的错误,请使用 errors()
方法。如果没有指定此方法,则默认错误为 '422' 和 '5**' 状态码。
使用状态码
$response = Retry::errors(422) ->retry(function () { return $this->client->request('GET', $url, $params); });
使用异常消息
$response = Retry::errors('Something exception message we should retry on.') ->retry(function () { return $this->client->request('GET', $url, $params); });
5** 状态码
由于500错误通常需要重试,因此您可以使用字符串 '5**' 匹配所有500级错误代码。
$response = Retry::errors('5**') ->retry(function () { return $this->client->request('GET', $url, $params); });
多个错误
要重试多个错误,请将状态码和消息的数组传递给 errors()
方法。
$response = Retry::errors([422,'5**', 'Something exception message we should retry on.']) ->retry(function () { return $this->client->request('GET', $url, $params); });
退避
backoff()
方法接受三个字符串之一来定义您的退避策略。
恒定策略
$response = Retry::backoff(BackoffStrategy::CONSTANT) ->retry(function () { $this->client->request('GET', $url, $params); });
线性退避策略
$response = Retry::backoff(BackoffStrategy::LINEAR) ->retry(function () { $this->client->request('GET', $url, $params); });
指数退避策略
$response = Retry::backoff(BackoffStrategy::EXPONENTIAL) ->retry(function () { $this->client->request('GET', $url, $params); });
限制重试尝试次数
为了避免无限期地重试下线服务,您可以设置最大尝试次数,使用 times()
方法。
$response = Retry::times(10) ->retry(function () { return $this->client->request('GET', $url, $params); });
限制延迟
为了防止您的策略无限期地增加延迟,您可以使用 maxDelay()
方法限制最大延迟。一旦达到此限制,后续的延迟将不会超过定义的最大延迟。
注意,单位是毫秒。(例如,6000ms == 60s)。
$response = Retry::maxDelay(6000) ->retry(function () { return $this->client->request('GET', $url, $params); });
锋利的刀具警告。
如果您没有指定最大睡眠时间,退避延迟将继续无限期地增加。同样,如果您没有指定最大尝试次数,请求将继续无限期地重试。
基础
您可以使用 base()
方法设置策略的新基础常量。以下示例将线性退避策略的基础设置为2。在这种情况下,第一次尝试延迟2秒,第二次4秒,第三次6秒,依此类推。
$response = Retry::base(2000) ->retry(function () { return $this->client->request('GET', $url, $params); });
抖动
通常,您会希望将抖动应用于您的退避策略,以避免与其他使用相同重试策略的客户竞争。 jitter()
方法接受三个字符串之一来定义您的抖动策略。
恒定抖动策略
$response = Retry::jitter(JitterStrategy::CONSTANT) ->retry(function () { $this->client->request('GET', $url, $params); });
相等抖动策略
$response = Retry::jitter(JitterStrategy::EQUAL) ->retry(function () { $this->client->request('GET', $url, $params); });
全抖动策略
$response = Retry::jitter(JitterStrategy::FULL) ->retry(function () { $this->client->request('GET', $url, $params); });
以下示例创建了一个使用指数退避和恒定抖动、基础1秒、最大延迟64秒和最多重试10次的可重试请求。
$response = Retry::backoff(JitterStrategy::EXPONENTIAL) ->jitter(JitterStrategy::CONSTANT) ->base(1000) ->times(10) ->maxRetries(64000) ->retry(function () { return $this->client->request('GET', $url, $params); });
可调用策略
除了流畅策略构建器之外,您还可以将可调用对象传递给 usingStrategy()
方法。这可以是一个回调或具有 __invoke()
方法的对象。异常对象作为第一个参数传递,可重试对象作为第二个参数传递。
可重试对象是一个简单的对象,用于跟踪您的重试策略被调用过的次数。您可以使用
getRetryAttempts()
方法获取重试尝试次数。您的调用函数应该始终返回一个布尔值。
$response = Retry::errors([422, '5**']) ->usingStrategy(function ($exception, $retryable) { if ($exception->getCode() == 422) { sleep(2); } if ($exception->getCode() >= 500) { sleep(4); } if ($retryable->getRetryAttempts > 5) { sleep(6); } })->retry(function () { return $this->client->request('GET', $url, $params); });
可调用决策器
如果确定失败请求是否应该重试的逻辑比匹配状态码或错误消息更复杂,您可以将一个可调用的函数传递给Retry
对象上的usingDecider()
方法。异常对象作为第一个参数传递,可重试对象作为第二个参数传递。
$response = Retry::usingDecider(function ($exception, $retryable) { if ($exception->getCode() == 422) { return true; } if ($retryable->getRetryAttempts() > 5) { return false; } return false; })->backoff(BackoffStrategy::CONSTANT) ->retry(function () { return $this->client->request('GET', $url, $params); })
致谢
感谢Caleb Porzio的建议、贡献以及说服我最初构建这个功能。