我刚刚发布了 Laravel 版的 Fuse。 在 2026 年印度 Laracon 大会上,我展示了这个软件包。它是为了解决一个困扰我不止一次的问题而开发的:当外部服务宕机时,队列工作进程会停止运行。
问题
想象一下这样的场景:晚上 11 点,Stripe 出现故障。你的队列处理程序并不知道这一点。它们继续尝试向客户收费,每个任务都会等待 30 秒超时后失败。然后它会重试。再次等待。再次超时。
如果你有 10,000 个支付任务排队等待,每个任务超时前都要等待 30 秒,那么即使每个请求都会失败,你也需要超过 25 个小时才能清理完队列。
Fuse 通过实现断路器模式来解决这个问题。在发生一定次数的失败后,它会完全停止发送请求。任务会在几毫秒内失败,而不是等待超时,并且会自动返回队列以供稍后重试。当服务恢复时,Fuse 会检测到并恢复正常运行。
断路器的工作原理
断路器有三种状态:
关闭 这是正常操作。所有请求都会直接发送到外部服务。在后台,Fuse 使用基于分钟的、自动过期的存储桶来跟踪成功率和失败率。
打开 处于保护模式。一旦故障率超过您配置的阈值,电路就会跳闸。作业现在会立即失败——不会进行 API 调用,也不会有 30 秒超时。作业会延迟一段时间后返回队列。您的队列会继续运行。
半开 这是恢复测试。经过一段超时时间(可针对每个服务进行配置)后,Fuse 允许一次探测请求通过。如果探测成功,电路关闭,恢复正常运行。如果探测失败,电路重新打开并再次等待。
安装
作曲家
要求
harris21/laravel-fuse
发布配置文件:
php
工匠
供应商:发布
--tag=fuse-config
基本用法
将中间件添加到任何调用外部服务的作业中:
使用
Harris21\Fuse\Middleware\CircuitBreakerMiddleware
;班级
收费客户
实现
应该排队{
民众
$尝试
=
0
;
民众
$maxExceptions
=
3
;
民众
功能
中间件
()
:
大批{
返回
[
新的
断路器中间件
(
'条纹'
)];}
民众
功能
处理
()
:
空白{
条纹
::
收费
()
->
创造
([
'数量'
=>
$this
->
数量,
'货币'
=>
美元
,
'顾客'
=>
$this
->
customerId,]);}}
环境
$tries = 0
允许无限次发布(因为在 Laravel 的意义上,已发布的作业并不等同于“重试”),而
$maxExceptions = 3
它能有效应对实际故障。这项工作本身不需要任何改动——Fuse 已经对其进行了全面封装。
配置
已发布的配置文件允许您设置默认值和每个服务的单独设置:
// config/fuse.php返回
[
‘已启用’
=>
环境
(
'FUSE_ENABLED'
,
真的
),
'default_threshold'
=>
50
,
'default_timeout'
=>
60
,
'default_min_requests'
=>
10
,
“服务”
=>
[
'条纹'
=>
[
'临界点'
=>
50
,
'暂停'
=>
30
,
'min_requests'
=>
5
,],
“邮枪”
=>
[
'临界点'
=>
60
,
'暂停'
=>
120
,
'min_requests'
=>
10
,],],];
这
threshold
这是一个失败率百分比。如果在跟踪窗口内 50% 的请求失败,则电路打开。
timeout
是测试恢复之前需要等待的秒数。
min_requests
防止电路在样本量过小时跳闸——至少需要这么多请求才能评估故障率。
智能故障分类
并非所有错误都意味着服务中断。例如,如果 Stripe 返回 429 错误,表示您已达到速率限制,这并不代表服务中断——服务运行正常,只是您发送的请求过多。身份验证错误也是如此。
保险丝只统计表明实际存在服务问题的故障:
- 500、502、503 服务器错误均计为故障。
- 连接超时和连接被拒绝均计为失败。
- 429 速率限制不计入
- 401 和 403 身份验证错误不计入在内。
这样可以防止误报。即使有人使用了过期的 API 密钥进行部署,您的电路也不会跳闸。
高峰时段支持
在营业时间内,您可能希望对交易失败有一定的容忍度,以最大限度地提高交易成功率。而在非营业时间,您可能更倾向于提前获得保护。Fuse 支持此功能:
'条纹'
=>
[
'临界点'
=>
40
,
'peak_hours_threshold'
=>
60
,
'peak_hours_start'
=>
9
,
'peak_hours_end'
=>
17
,],
上午 9 点至下午 5 点,电路使用 60% 的阈值。其他时间,则使用 40%。这样,您可以根据交易的关键时段,灵活调整安全性和吞吐量之间的平衡。
活动
Fuse 会在每次状态转换时触发 Laravel 事件:
使用
Harris21\Fuse\Events\CircuitBreakerOpened
;使用
Harris21\Fuse\Events\CircuitBreakerHalfOpen
;使用
Harris21\Fuse\Events\CircuitBreakerClosed
;
您可以收听这些提醒:
班级
电路开路警报{
民众
功能
处理
(
断路器已打开
$event)
:
空白{
日志
::
批判的
(
“电路已为{
$事件
->
服务
}”
,[
'失败率'
=>
$事件
->
故障率
“尝试”
=>
$事件
->
尝试,
“失败”
=>
$事件
->
失败,]);
// 发送到 Slack、值班页面等。}}
这
CircuitBreakerOpened
事件信息包括服务名称、当前故障率、总尝试次数和故障计数。这些信息足以满足调试和告警的需求。
直接使用
您也可以在已排队作业之外使用断路器:
使用
Harris21\保险丝\断路器
;$breaker
=
新的
断路器
(
'条纹'
(英文):如果
(
!
$breaker
->
isOpen
()){
尝试
{$结果
=
条纹
::
收费
()
->
创造
([
...
]);$breaker
->
记录成功
();
返回
$结果;}
抓住
(
例外
$e) {$breaker
->
记录失败
($e);
扔
等;}}
别的
{
返回
$this
->
备用响应
();}
您还可以手动检查状态并重置:
$breaker
->
已关闭
();$breaker
->
isOpen
();$breaker
->
半开
();$breaker
->
获取统计数据
();$breaker
->
重置
();
雷鸣群预防
当电路进入半开状态时,你肯定不希望 50 个队列工作进程同时发送探测请求。Fuse 使用
Cache::lock()
确保只有一个工作进程测试服务。其他进程会持续快速失败,直到探测完成。
要求
- PHP 8.3+
- Laravel 11+
- 任何 Laravel 缓存驱动(生产环境推荐使用 Redis)
该软件包没有任何外部依赖项。它使用 Laravel 的原生缓存系统进行跟踪和锁定。
链接
- GitHub: harris21/laravel-fuse
断路器模式源自迈克尔·尼加德 放手! 后来由 Martin Fowler 推广开来。Fuse 将其引入 Laravel,提供原生集成,基本用例无需任何配置。





