atlastechnol/laravel-5.5-circuit-breaker

基于laravel circuit breaker package https://github.com/francescomalatesta/laravel-circuit-breaker的Laravel框架5.5电路断路器模式实现

0.1.4 2022-09-06 16:23 UTC

This package is auto-updated.

Last update: 2024-09-25 21:03:04 UTC


README

Laravel框架5.6的Circuit Breaker模式实现。

Latest Version on Packagist Software License Build Status Quality Score StyleCI

如果你需要为你的Laravel应用程序提供一个易于使用的Circuit Breaker模式实现,你就在正确的位置。

注意:本包基于laravel circuit breaker package https://github.com/francescomalatesta/laravel-circuit-breaker,在此仓库中增加了对Laravel 5.5及以下版本的兼容性,仅在Laravel 5.5上进行了测试。

安装

你可以使用Composer为你的项目安装此包。

$ composer require atlas/laravel-circuit-breaker

不用担心服务提供者和外观:Laravel可以在不进行任何操作的情况下自动发现此包!

只需记住,使用以下命令 发布配置文件

php artisan vendor:publish

用法

你将始终使用单个类(CircuitBreaker外观或如果你想注入它则使用CircuitBreakerManager类)来使用此包。

以下是方法参考

isAvailable(string $identifier) : bool

如果服务$identifier目前可用,则返回true。否则返回false

注意:你可以使用任何你想要的作为标识符。如果可能的话,我喜欢使用MyClass::class名称。

reportFailure(string $identifier) : void

报告对服务$identifier的失败尝试。查看下面的配置部分,了解如何管理尝试和失败次数。

reportSuccess(string $identifier) : void

报告对服务$identifier的成功尝试。你可以用它来标记一个服务为可用,并从它那里删除“失败”状态。

配置

默认值

通过编辑config/circuit_breaker.php配置文件内容,你可以根据你的需求调整电路断路器。

default项下有三个值

<?php

return [
    'defaults' => [
        'attempts_threshold' => 3,
        'attempts_ttl' => 1,
        'failure_ttl' => 5
    ],
    
    // ...
];
  • attempts_threshold:用于指定在声明服务“失败”之前需要进行的尝试次数 - 默认:3;
  • attempts_ttl:用于指定在声明服务“失败”之前需要进行的尝试的时间窗口(以分钟为单位) - 默认:1;
  • failure_ttl:一旦服务被标记为“失败”,它将保持此状态,持续此数量的分钟数 - 默认:5;

为了更好地理解:默认情况下,1分钟内3次失败的尝试将导致服务在5分钟内“失败”。

服务映射

调整配置文件很酷,但如果我需要为特定的服务设置特定的TTL和尝试次数怎么办?没问题:这里的services选项就是为了帮助。

如你在config/circuit_breaker.php配置文件中看到的,你还有一个services项。你可以在这里指定单个服务的设置。以下是一个示例

<?php

return [
    'defaults' => [
        'attempts_threshold' => 3,
        'attempts_ttl' => 1,
        'failure_ttl' => 5
    ],
    
    'services' => [
        'my_special_service_identifier' => [
            'attempts_threshold' => 2,
            'attempts_ttl' => 1,
            'failure_ttl' => 10
        ]
    ]
];

然后,当你调用CircuitBreaker::reportFailure('my_special_service_identifier')时,电路断路器将识别“特殊”服务并使用特定的配置设置、TTL和尝试次数。

小贴士:你还可以在 service 数组中覆盖单个服务的设置。其他设置将使用默认值合并。

使用示例

假设我们有一个用于应用的支付网关集成。我们将这个类命名为 PaymentsGateway

现在,假设这是一个第三方服务:有时它可能需要暂时关闭。然而,我们不希望阻止用户购买商品,所以如果 PaymentsGateway 服务不可用,我们希望将订单重定向到名为 DelayedPaymentsGateway 的备用服务,该服务将简单地“排队”延迟订单以在将来处理。

以下是在 BuyArticleOperation 类中模拟此过程。

<?php

class BuyArticleOperation {
    
    /** @var PaymentsGateway */
    private $paymentsGateway;
    
    /** @var DelayedPaymentsGateway */
    private $delayedPaymentsGateway;
    
    public function process(string $orderId)
    {
       // doing stuff with my order and then...
       
       try {
           $this->paymentsGateway->attempt($orderId);
       } catch (PaymentsGatewayException $e) {
           // something went wrong, let's switch the payment
           // to the "delayed" queue system
           $this->delayedPaymentsGateway->queue($orderId);
       }
    }
}

太好了!现在我们可以100%确信我们的支付将被处理。有时候这还不够。

你知道,也许 PaymentsGateway 需要至少5秒钟来完成单个尝试,而你的应用每分钟接收数百个订单。即使我们在第一次尝试后就“知道”它不起作用,反复调用 PaymentsGateway 真的有帮助吗?

这就是如何使用这个断路器编写你的代码。

<?php

use CircuitBreaker;
use My\Namespace\PaymentsGateway;
use My\Namespace\DelayedPaymentsGateway;

class BuyArticleOperation {
    
    /** @var PaymentsGateway */
    private $paymentsGateway;
    
    /** @var DelayedPaymentsGateway */
    private $delayedPaymentsGateway;
    
    public function process(string $orderId)
    {
        if(CircuitBreaker::isAvailable(PaymentsGateway::class)) {
            try {
                $this->paymentsGateway->attempt($orderId);
            } catch (PaymentsGatewayException $e) {
                // something went wrong, let's switch the payment
                // to the "delayed" queue system and report that
                // the default gateway is not working!
                $this->delayedPaymentsGateway->queue($orderId);
                CircuitBreaker::reportFailure(PaymentsGateway::class);
            }
            
            // there's nothing we can do here anymore
            return;
        }
        
        // we already know that the service is disabled, so we
        // can queue the payment process on the delayed queue
        // directly, without letting our users wait more
        $this->delayedPaymentsGateway->queue($orderId);
    }
}

假设我们正在10秒内处理100个订单(在不同的进程中)。

  • 对于第一个订单,我们要求 PaymentsGateway 处理,但出了点问题;
  • 我们在 DelayedPaymentsGateway 上排队支付,并向 CircuitBreaker 报告失败;
  • 2号和3号订单也是这样;
  • 在处理完第三笔订单后,CircuitBreaker 决定在3次尝试(且在不到1分钟内)后,可以声明 PaymentsGateway “失败”,我们可以直接使用我们的备用服务 DelayedPaymentsGateway 一段时间(5分钟);
  • 剩余的97个订单被排队并成功处理,而没有浪费很多时间(97 * 5 = 485处理秒)在明显不会工作的服务上;

酷,不是吗? :)

测试

你可以轻松地执行测试,

$ vendor/bin/phpunit

即将推出

  • 指数退避失败TTLs;
  • 设置小于1分钟的TTLs;
  • 使底层存储实现可定制;

贡献

请参阅CONTRIBUTINGCODE_OF_CONDUCT 了解详细信息。

安全

如果你发现任何安全问题,请通过电子邮件 francescomalatesta@live.it 反馈,而不是使用问题跟踪器。

鸣谢

许可

MIT 许可证(MIT)。有关更多信息,请参阅 许可文件