PHP 的无装饰熔断器

2.0.0 2023-05-23 14:14 UTC

This package is not auto-updated.

Last update: 2024-09-25 19:01:46 UTC


README

此应用程序实现了 PHP 的熔断器。目前它提供由 APC 支持的不安全熔断器。它受到了 jlouis 在 erlang 中实现的熔断器的极大启发,您可以在 这里 找到。

Build Status

安装

安装就像运行

$ composer require fabiomsouto/phuse

变更日志

此项目遵循 语义版本控制

2.0.0

[变更]

  • 将覆盖 SplSubject 方法的类方法添加了返回类型,以避免在 php8.1 中出现 E_DEPRECATED 通知,因为方法签名需要相等才能被认为是兼容的。

1.1.0

[新增]

  • PHP7 兼容性

[变更]

  • 改进 phpdocs

1.0.1

[新增]

  • 为附加/分离观察者的单元测试
  • 为获取器进行的单元测试
  • 这使得我们目前提供的唯一熔断器的单元测试覆盖率达到了 100% :)

[变更]

  • 内部,观察者现在存储在一个 SplObjectStorage 对象中。

1.0.0

[新增]

  • 熔断器现在也是一个 SplSubject。这样,您可以将 SplObserver 实例附加到它上,并在熔断器熔化或重启时收到通知。
  • 添加了 phpunit.xml 规范,因此您可以轻松运行单元测试。

[变更]

  • README.md 中的几个链接不起作用,已修复这些问题。
  • 向一些单元测试中添加了一些断言,以提供额外的安全性。

0.0.1

[新增]

  • 不安全的 APC 熔断器实现:一个异步熔断器,它依赖于 APC 来存储状态。
  • FuseBox,用于生成熔断器的工厂
  • 基本单元测试

什么是熔断器?

熔断器是一个组件,在熔化后内部短路,类似于现实生活中的熔断器。

它能为我的应用做什么?

熔断器可以帮助您的应用在需要与外部系统通信时更加可靠。假设您的应用 A 与应用 B 通信。如果 B 开始超时或抛出错误,您的应用会如何表现?具体来说,在 PHP 中,如果您有一个 REST 服务,并且它需要同步击中外部端点,外部服务的延迟将导致您的服务具有增加的延迟,锁定工作进程等。熔断器可以位于其中。当您检测到故障时,您会“熔化”熔断器。经过一定次数的熔化后,熔断器“爆炸”,一段时间内将不会接触您的服务,从而打破这个依赖链。然后,您的服务可以更快地失败,或相应地反应(例如,联系备用服务)。

如何使用熔断器(教程)?

很简单。首先实例化一个熔断器

$M = 10;
$T = 100;
$R = 1000;
$fuse = FuseBox::getUnsafeApcInstance("database", $M, $T, $R);

这将设置一个名为 database 的熔断器。 $M 是熔断器可以承受的熔化次数。 $T 是这些熔化可以发生的时间间隔。因此,在这种情况下,如果 10 次熔化在 100ms 内发生,则熔断器爆炸。熔断器爆炸后,它将在 $R 毫秒后重启,在这种情况下为 1000ms。

在您的熔断器设置完成后,您的应用程序可以询问其状态

$M = 10;
$T = 100;
$R = 1000;
$fuse = FuseBox::getUnsafeApcInstance("database", $M, $T, $R);
if ($fuse->ok()) {
    // do whatever
}

这是愉快的情况。但现在假设您正在向某个端点进行 POST,并且它出现错误

$M = 10;
$T = 100;
$R = 1000;
$fuse = FuseBox::getUnsafeApcInstance("database", $M, $T, $R);

...

try {
   $result = $curl->post($url, $data);
}
catch (Exception $e) {
    $fuse->melt();
}

您正在向保险丝发出信号,表示存在问题。如果保险丝在一定时间内熔断次数过多,它会熄灭,并保持熄灭状态,直到冷却下来。

我该如何监控保险丝呢?

从Fuse接口继承的每个保险丝也是一个SplSubject。因此,您可以为保险丝创建一个SplObserver并将其注册。每当保险丝熔断或重启时,观察者都会收到通知。

class AFuseObserver implements SplObserver {
    public function update(SplSubject $subject)
    {
        $blown = $subject->blown();
        echo "This fuse is now ";
        echo $blown? "blown\n" : "not blown\n";
    }
}

...

$M = 10;
$T = 100;
$R = 1000;
$fuse = FuseBox::getUnsafeApcInstance("database", $M, $T, $R);
$observer = new AFuseObserver();
$fuse->attach($observer);

// when the fuse melts you will see something in your terminal
$fuse->melt();
// outputs "This fuse is now blown" when the threshold is reached

...
// after 1000ms...
$fuse->ok();
// outputs "This fuse is now not blown" when the restart period ends

请注意,通知观察者可能需要很长时间。因此,请确保更新调用尽可能简洁,并确保您没有在每次保险丝中注册大量观察者,因为通知所有观察者是一个O(n)操作。

性能

这将很快可用。

测试

提供了一些PHPUnit测试。如果您想做出贡献,请确保为您的贡献提供单元测试。