postcon / resilience
弹性助手库
v1.0.3
2021-08-04 11:33 UTC
Requires
- php: >=7.1
- ext-redis: *
Requires (Dev)
- guzzlehttp/guzzle: ^6.3
- phpunit/phpunit: ^7.0 || ^8.0
- psr/http-message: ^1.0
This package is auto-updated.
Last update: 2024-09-04 17:56:26 UTC
README
一组可重用的弹性模式实现。目前实现包括
安装
使用 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许可证许可。