mingalevme/retryable-psr-http-client

该软件包提供了一个熟悉的PSR HTTP客户端接口,具有自动重试和指数退避(以及其他策略)。它是对标准PSR HTTP客户端的轻量级封装,并公开相同的API。这使得装饰器非常容易集成到现有程序中。

2.0.0 2024-07-05 10:42 UTC

This package is auto-updated.

Last update: 2024-09-05 11:11:27 UTC


README

quality codecov version license

简单的带有 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);
    },
);