介紹
Guzzle
是 PHP 的一款HTTP客戶端包,這裡介紹如何使用Guzzle提供的中介軟體來進行請求失敗後的重試,
關於中介軟體的介紹可以檢視文件:Handlers and Middleware
使用
先來看看Guzzle
原始碼中 retry
中介軟體的定義:
/**
* Middleware that retries requests based on the boolean result of
* invoking the provided "decider" function.
*
* If no delay function is provided, a simple implementation of exponential
* backoff will be utilized.
*
* @param callable $decider Function that accepts the number of retries,
* a request, [response], and [exception] and
* returns true if the request is to be retried.
* @param callable $delay Function that accepts the number of retries and
* returns the number of milliseconds to delay.
*
* @return callable Returns a function that accepts the next handler.
*/
public static function retry(callable $decider, callable $delay = null)
{
return function (callable $handler) use ($decider, $delay) {
return new RetryMiddleware($decider, $handler, $delay);
};
}
retry 接收兩個引數:
- $decider:重試決策,型別是
callable
,中介軟體根據該回撥函式的返回值來決定是否進行重試。回撥函式接收四個引數,分別是:當前重試次數,當前請求(GuzzleHttp\Psr7\Request),當前響應(GuzzleHttp\Psr7\Response), 當前發生的異常 (GuzzleHttp\Exception\RequestException),回撥函式返回true/false,表示繼續重試/停止重試 - $delay:重試延遲時間,型別也是
callable
,中介軟體根據該回撥函式返回的值來延遲下次請求的時間,回撥函式接收一個引數,是當前重試的次數,該回撥函式返回下次重試的時間間隔
所以根據Retry中介軟體的定義,我們有如下的程式碼:
<?php
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
class TestGuzzleRetry
{
/**
* 最大重試次數
*/
const MAX_RETRIES = 5;
/**
* @var Client
*/
protected $client;
/**
* GuzzleRetry constructor.
*/
public function __construct()
{
// 建立 Handler
$handlerStack = HandlerStack::create(new CurlHandler());
// 建立重試中介軟體,指定決策者為 $this->retryDecider(),指定重試延遲為 $this->retryDelay()
$handlerStack->push(Middleware::retry($this->retryDecider(), $this->retryDelay()));
// 指定 handler
$this->client = new Client(['handler' => $handlerStack]);
}
/**
* retryDecider
* 返回一個匿名函式, 匿名函式若返回false 表示不重試,反之則表示繼續重試
* @return Closure
*/
protected function retryDecider()
{
return function (
$retries,
Request $request,
Response $response = null,
RequestException $exception = null
) {
// 超過最大重試次數,不再重試
if ($retries >= self::MAX_RETRIES) {
return false;
}
// 請求失敗,繼續重試
if ($exception instanceof ConnectException) {
return true;
}
if ($response) {
// 如果請求有響應,但是狀態碼大於等於500,繼續重試(這裡根據自己的業務而定)
if ($response->getStatusCode() >= 500) {
return true;
}
}
return false;
};
}
/**
* 返回一個匿名函式,該匿名函式返回下次重試的時間(毫秒)
* @return Closure
*/
protected function retryDelay()
{
return function ($numberOfRetries) {
return 1000 * $numberOfRetries;
};
}
}