postcon/resilience

弹性助手库

v1.0.3 2021-08-04 11:33 UTC

This package is auto-updated.

Last update: 2024-09-04 17:56:26 UTC


README

Build Status

一组可重用的弹性模式实现。目前实现包括

安装

使用 composer

composer require postcon/resilience

简单用法

$redis = new \Redis();

$circuitBreaker = new \Postcon\Resilience\RedisCircuitBreaker($redis, 'system', 120, 3);
$circuitBreaker->reportSuccess();

$circuitBreaker->isAvailable(); // should be true
$circuitBreaker->reportFailure();
$circuitBreaker->isAvailable(); // ... still true
$circuitBreaker->reportFailure();
$circuitBreaker->isAvailable(); // ... still true
$circuitBreaker->reportFailure();
$circuitBreaker->isAvailable(); // ... now it is false

$circuitBreaker->check(); // throws CircuitBreakerTripped exception, if 'system' is not available.

状态转换

断路器可以是以下三种状态之一:关闭(系统可用)、半开(系统仍然可用)和打开(系统不可用)。

断路器的默认状态是关闭;即系统正在正常运行。如果报告了故障,状态将变为半开。如果报告了成功,或者定义的时间超过(生命周期),状态将再次变为关闭。如果反复报告故障(最大错误数),状态将从半开变为打开(断路器被触发)。

在超过定义的时间后,打开状态将变回关闭。根据此断路器实现的用法,报告的成功也可能将打开状态变为关闭。

 --------------------------      ::reportSuccess()        ---------------------------
|          CLOSED          | <-------------------------- |            OPEN           |
| ::isAvailable() === true |    exceeding lifetime       | ::isAvailable() === false |
 --------------------------                               ---------------------------
       ^      |                                                                 ^
       |      |   ::reportFailure()                                             |
       |       -------------------------                                        |
       |                                |                                       |
       |                                v                                       |
       |  ::reportSuccess()   --------------------------                        |
        -------------------- |         HALF OPEN        | ----------------------
         exceeding lifetime  | ::isAvailable() === true |  rpt. ::reportFailure()
                              --------------------------

示例

此断路器实现可用于装饰例如guzzle http 客户端

use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\ServerException;
use Postcon\Resilience\CircuitBreakerInterface;
use Postcon\Resilience\CircuitBreakerTripped;
use Psr\Http\Message\RequestInterface;

class CircuitBreakerClientDecorator implements ClientInterface
{
    /** @var ClientInterface */
    private $baseClient;

    /** @var CircuitBreakerInterface */
    private $circuitBreaker;

    public function __construct(ClientInterface $baseClient, CircuitBreakerInterface $circuitBreaker)
    {
        $this->baseClient     = $baseClient;
        $this->circuitBreaker = $circuitBreaker;
    }

    /**
     * @inheritdoc
     *
     * @throws CircuitBreakerTripped
     */
    public function send(RequestInterface $request, array $options = [])
    {
        return $this->check(function () use ($request, $options) {
            $this->baseClient->send($request, $options);
        });
    }

    // ...

    /**
     * @throws GuzzleException
     * @throws CircuitBreakerTripped
     */
    private function check(callable $function)
    {
        $this->circuitBreaker->check();

        try {
            $result = $function();

            $this->circuitBreaker->reportSuccess();

            return $result;
        } catch (ConnectException $e) {
            $this->circuitBreaker->reportFailure();
            throw $e;
        } catch (ServerException $e) {
            $this->circuitBreaker->reportFailure();
            throw $e;
        } catch (ClientException $e) {
            $this->circuitBreaker->reportSuccess();
            throw $e;
        }
    }
}

实现细节

目前,有一个redis 实现的断路器模式。断路器的实例作为相应的错误计数器持久化,其中redis键是断路器名称。

要实现生命周期功能(在一段时间后自动状态转换到关闭),使用redis EXPIRE命令

许可证

本软件包所有内容均受MIT许可证许可。