endisha/resilient-client

Resilient Client 是一个 PHP 包,旨在实现断路器模式,以增强稳定性和防止级联故障请求。

1.0.1 2023-09-05 13:15 UTC

This package is auto-updated.

Last update: 2024-09-05 15:17:56 UTC


README

Latest Stable Version Total Downloads

Resilient Client 是一个 PHP 包,旨在实现断路器模式,以增强稳定性和防止级联故障请求。

什么是断路器模式?

断路器是一种在软件开发中使用的模式。它用于检测和防止由于网络连接缓慢、超时、不可用或意外系统困难导致的级联请求故障。

要求

  • PHP ^8.1 或更高版本

安装

您可以通过运行以下命令使用 Composer 安装此包:

composer require endisha/resilient-client

用法

要在项目中使用此包,请包含 Composer 的自动加载文件

require_once __DIR__ . '/vendor/autoload.php';

实现断路器模式

use ResilientClient\CircuitBreaker;
use ResilientClient\CircuitBreaker\Adapters\FileStorageAdapter;

$adapter = new FileStorageAdapter;
$adapter->setPath(__DIR__ . '/storage/');

$circuitBreaker = new CircuitBreaker($adapter);
// The maximum number of consecutive failures that can occur before the circuit breaker trips and enters a [failed] state
$circuitBreaker->setFailureThreshold(3);
// The duration that the circuit breaker waits in an [open] state before allowing test requests to determine if the service has recovered (In seconds)
$circuitBreaker->setResetTimeout(300);

CircuitBreaker 构造函数还允许将自定义键作为第二个参数设置;默认值为 default

$circuitBreaker = new CircuitBreaker($adapter, 'github-cb');

适配器

此包支持两种类型的适配器,每种适配器都作为断路器模式的状态存储方法

  • 文件存储适配器:在文件中存储状态。
  • PDO 数据库适配器:使用 PDO 在数据库中存储状态。

文件存储适配器

要使用文件存储适配器并将电路状态保存到文件中,请使用 FileStorageAdapter 并按照以下步骤操作:

use ResilientClient\CircuitBreaker\Adapters\FileStorageAdapter;
$adapter = new FileStorageAdapter;
$adapter->setPath('path/to/storage');

数据库(PDO)适配器

要使用数据库(PDO)适配器并使用 PDO 在 circuit_breaker 表中保存状态,您需要首先创建自定义表

CREATE TABLE `circuit_breaker` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `key` varchar(40) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
  `state` varchar(40) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
  `failure_count` int(11) NOT NULL,
  `last_failure_time` int(11) DEFAULT NULL,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

创建 PDODatabaseAdapter 类的实例

use ResilientClient\CircuitBreaker\Adapters\PDODatabaseAdapter;
use PDO;

// PDO connection
$pdo = new PDO("mysql:host=localhost;dbname=name", 'user', 'pass');
// Use PDODatabaseAdapter
$adapter = new PDODatabaseAdapter($pdo);
$adapter->setTable('circuit_breaker'); //table: circuit_breaker

工作原理

  • 要检查电路是否打开(不可用),请使用:
$circuit->isNotAvaiable();
  • 要将请求标记为成功,请使用:
$circuit->success();
  • 要将请求标记为失败,请使用:
$circuit->failure();

示例

use ResilientClient\CircuitBreaker\Adapters\FileStorageAdapter;
use ResilientClient\CircuitBreaker\CircuitBreaker;
use ResilientClient\CircuitBreaker\Exceptions\CircuitBreakerException;

$adapter = new FileStorageAdapter;
$adapter->setPath(__DIR__ . '/storage/');

$circuitBreaker = new CircuitBreaker($adapter);
$circuitBreaker->setFailureThreshold(3);
$circuitBreaker->setResetTimeout(300);

try {

    if ($circuitBreaker->isNotAvailable()) {
        throw new CircuitBreakerException('Service is unreachable');
    }

    // Send request
    // ....
    $successRequest = true;
    // ....

    if ($successRequest) {
        $circuitBreaker->success();
    } else {
        $circuitBreaker->failure();
    }
} catch (\CircuitBreakerException $e) {
    echo $e->getMessage();
}

Guzzle 集成

此包通过 CircuitBreakerGuzzleMiddleware 中间件支持与 Guzzle 的集成。当由于连接到远程服务器或建立连接的问题而抛出 ConnectException 异常时,将自动实现此中间件。要实现它,请按照以下步骤操作:

use GuzzleHttp\Client;
use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\HandlerStack;
use ResilientClient\CircuitBreaker\Middleware\CircuitBreakerGuzzleMiddleware;

$stack = HandlerStack::create(new CurlHandler());
$middleware = new CircuitBreakerGuzzleMiddleware($circuitBreaker);
$stack->push($middleware);

$args['handler'] = $stack;
$client = new Client($args);
// etc..

此外,您可以指定某些 HTTP 状态代码作为失败请求。例如,您可能希望将错误 301(永久移动)和 302(找到)视为失败响应

use GuzzleHttp\Client;
use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\HandlerStack;
use ResilientClient\CircuitBreaker\Middleware\CircuitBreakerGuzzleMiddleware;

$stack = HandlerStack::create(new CurlHandler());
$middleware = new CircuitBreakerGuzzleMiddleware($circuitBreaker);
$middleware->setAsFailureRequestCodes(301, 302);
$stack->push($middleware);

$args['handler'] = $stack;
$client = new Client($args);
// etc..

异常处理

当断路器处于打开状态时,它抛出 ResilientClient\CircuitBreaker\Exceptions\CircuitBreakerException 异常类。此异常作为电路当前打开且不允许对服务进行请求的信号。您可以通过捕获此异常在电路打开时在您的应用程序中实现自定义处理逻辑。

示例用法

use GuzzleHttp\Client;
use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\HandlerStack;
use ResilientClient\CircuitBreaker\Adapters\FileStorageAdapter;
use ResilientClient\CircuitBreaker\CircuitBreaker;
use ResilientClient\CircuitBreaker\Middleware\CircuitBreakerGuzzleMiddleware;

$adapter = new FileStorageAdapter;
$adapter->setPath(__DIR__ . '/storage/');

$circuitBreaker = new CircuitBreaker($adapter);
$circuitBreaker->setFailureThreshold(3);
$circuitBreaker->setResetTimeout(300);

$stack = HandlerStack::create(new CurlHandler());

$middleware = new CircuitBreakerGuzzleMiddleware($circuitBreaker);
$middleware->setAsFailureRequestCodes(301, 302);
$stack->push($middleware);

$args['handler'] = $stack;
$client = new Client($args);
// etc..

测试

composer test

许可

Resilient Client 包是开源软件,在 MIT 许可证下发布。