mingalevme / retryable-psr-http-client
该软件包提供了一个熟悉的PSR HTTP客户端接口,具有自动重试和指数退避(以及其他策略)。它是对标准PSR HTTP客户端的轻量级封装,并公开相同的API。这使得装饰器非常容易集成到现有程序中。
2.0.0
2024-07-05 10:42 UTC
Requires
- php: ^8.0
- psr/clock: ^1.0
- psr/http-client: ^1.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.13
- guzzlehttp/psr7: ^2.4
- mingalevme/psr-http-client-stubs: ^2.0
- phpstan/phpstan: ^1.9
- phpunit/phpunit: ^9.5
- squizlabs/php_codesniffer: ^3.7
- vimeo/psalm: ^5.1
Provides
This package is auto-updated.
Last update: 2024-09-05 11:11:27 UTC
README
简单的带有 Retry-After 头支持的 100% 代码覆盖率的重试PSR HTTP客户端装饰器。
注意: 默认情况下禁用了 Retry-After 头的处理,因为依赖于不受信任的头信息是危险的,只有在完全理解后果的情况下才启用。
Composer
composer require mingalevme/retryable-psr-http-client
示例 1(简单替换)
- 最大 3 次尝试。
- 在 5xx/429 响应状态码和/或
Psr\Http\Client\ClientExceptionInterface
触发。 - 指数退避:尝试次数的2次幂(1,2,4,8,...)。
use Mingalevme\RetryablePsrHttpClient\RetryablePsrHttpClient; use Psr\Http\Client\ClientInterface; $someDiContainer->decorate(ClientInterface::class, function (ClientInterface $client): RetryablePsrHttpClient { return new RetryablePsrHttpClient($client); });
示例 2(扩展使用)
- 最大 5 次尝试。
- 尊重 Retry-After 头。
- 线性退避,初始值1秒 + 斜率2秒。
- 在4xx、5xx和
Psr\Http\Client\ClientExceptionInterface
触发。 - 在任何错误(不可接受响应或
Psr\Http\Client\ClientExceptionInterface
-异常)时记录日志。
<?php use Mingalevme\RetryablePsrHttpClient\BackoffCalc\LinearBackoffCalc; use Mingalevme\RetryablePsrHttpClient\Config; use Mingalevme\RetryablePsrHttpClient\NullEventListener; use Mingalevme\RetryablePsrHttpClient\ResponseAnalyzer\ResponseAnalyzerInterface; use Mingalevme\RetryablePsrHttpClient\RetryablePsrHttpClient; use Psr\Http\Client\ClientExceptionInterface; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use Psr\Log\LoggerInterface; final class MyAppHttpClientErrLogEventListener extends AbstractEventListener { public function __construct( private LoggerInterface $logger, ) { } public function onError( int $attemptNumber, RequestInterface $request, ClientExceptionInterface|ResponseInterface $error, ): void { $this->logger->error("Error while sending request {$request->getUri()}, attempt #$attemptNumber"); } } final class MyAppHttpResponseAnalyzer implements ResponseAnalyzerInterface { public function isAcceptable(ResponseInterface $response): bool { return $response->getStatusCode() >= 400; } } $someDiContainer->decorate( ClientInterface::class, function ( ClientInterface $client, MyAppHttpClientErrLogEventListener $listener, MyAppHttpResponseAnalyzer $responseAnalyzer, ): RetryablePsrHttpClient { $config = Config::new() ->setRetryCount(5) ->setRespectRetryAfterHeader(true) ->setBackoffCalc(new LinearBackoffCalc(2, 1)) ->setResponseAnalyzer($responseAnalyzer) ->addEventListener($listener); return new RetryablePsrHttpClient($client, $config); }, );