gabrielanhaia/laravel-circuit-breaker
Composer 安装命令:
composer require gabrielanhaia/laravel-circuit-breaker
包简介
Laravel integration for PHP Circuit Breaker — multiple storage drivers, middleware, Artisan commands, and event system
README 文档
README
A Laravel integration for PHP Circuit Breaker v3 with multiple storage drivers, HTTP middleware, Artisan commands, and full event system integration.
What Is a Circuit Breaker?
When your application calls an external service (payment gateway, email API, etc.), that service can become slow or unresponsive. Without protection, your application keeps sending requests — piling up timeouts, wasting resources, and degrading user experience.
A circuit breaker monitors failures and automatically stops calling a failing service, giving it time to recover. It works like an electrical circuit breaker: when too many failures occur, the circuit "opens" and all requests fail fast without actually hitting the remote service.
stateDiagram-v2
[*] --> Closed
Closed --> Open : Failures reach threshold
Open --> HalfOpen : Timeout expires
HalfOpen --> Closed : Success threshold met
HalfOpen --> Open : Any failure
Loading
| State | Behaviour |
|---|---|
| Closed | Normal operation. Requests pass through. Failures are counted. |
| Open | Requests are blocked immediately (fail fast). No calls reach the service. |
| Half-Open | A limited number of probe requests are allowed through to test recovery. |
Requirements
- PHP ^8.2
- Laravel ^11.0 or ^12.0
- gabrielanhaia/php-circuit-breaker ^3.0 (installed automatically)
Installation
composer require gabrielanhaia/laravel-circuit-breaker
Publish the configuration file:
php artisan vendor:publish --tag=circuit-breaker-config
Configuration
After publishing, the config lives at config/circuit_breaker.php.
Storage Driver
Choose where circuit state is persisted:
<?php // config/circuit_breaker.php return [ 'default_driver' => env('CIRCUIT_BREAKER_DRIVER', 'redis'), 'drivers' => [ 'redis' => [ 'connection' => env('CIRCUIT_BREAKER_REDIS_CONNECTION', 'default'), 'prefix' => 'cb:', ], 'apcu' => [ 'prefix' => 'cb:', ], 'memcached' => [ 'connection' => env('CIRCUIT_BREAKER_MEMCACHED_CONNECTION', 'memcached'), 'prefix' => 'cb:', ], 'array' => [], ], // ... ];
| Driver | Best for | Requirement |
|---|---|---|
redis |
Distributed / multi-server apps | ext-redis (phpredis) |
apcu |
Single-server, high performance | ext-apcu |
memcached |
Distributed caching | ext-memcached |
array |
Testing and local development | none |
Note: The Redis driver requires the phpredis PHP extension. Predis is not supported by the underlying storage adapter.
Default Thresholds
<?php // config/circuit_breaker.php return [ // ... 'defaults' => [ 'failure_threshold' => 5, // Number of failures to open the circuit 'success_threshold' => 1, // Successes in half-open to close the circuit 'time_window' => 20, // Seconds in which failures are counted 'open_timeout' => 30, // Seconds the circuit stays open before half-open 'half_open_timeout' => 20, // Seconds the circuit stays half-open 'exceptions_enabled' => false, // true = throw OpenCircuitException instead of returning false ], // ... ];
Per-Service Overrides
Different services can have different thresholds. Any key you omit falls back to the value in defaults:
<?php // config/circuit_breaker.php return [ // ... 'services' => [ 'payment-api' => [ 'failure_threshold' => 3, // More sensitive — fewer failures to trip 'open_timeout' => 60, // Longer cooldown ], 'email-service' => [ 'failure_threshold' => 10, // More tolerant ], ], ];
Usage
Facade
<?php namespace App\Services; use GabrielAnhaia\LaravelCircuitBreaker\Facades\CircuitBreaker; use Illuminate\Support\Facades\Http; class PaymentService { public function charge(array $data): mixed { if (!CircuitBreaker::canPass('payment-api')) { return $this->fallback(); } try { $response = Http::timeout(5)->post('https://api.payment.example/charge', $data); CircuitBreaker::recordSuccess('payment-api'); return $response->json(); } catch (\Throwable $e) { CircuitBreaker::recordFailure('payment-api'); return $this->fallback(); } } private function fallback(): array { return ['status' => 'queued', 'message' => 'Payment will be retried shortly.']; } }
Dependency Injection
<?php namespace App\Services; use GabrielAnhaia\LaravelCircuitBreaker\CircuitBreakerManager; use Illuminate\Support\Facades\Http; class PaymentService { public function __construct( private readonly CircuitBreakerManager $circuitBreaker, ) {} public function charge(array $data): mixed { if (!$this->circuitBreaker->canPass('payment-api')) { return $this->fallback(); } try { $response = Http::timeout(5)->post('https://api.payment.example/charge', $data); $this->circuitBreaker->recordSuccess('payment-api'); return $response->json(); } catch (\Throwable $e) { $this->circuitBreaker->recordFailure('payment-api'); return $this->fallback(); } } private function fallback(): array { return ['status' => 'queued']; } }
HTTP Middleware
The circuit-breaker middleware wraps an entire route. It blocks requests when the circuit is open and automatically records successes and failures based on the HTTP status code.
flowchart LR
A[Incoming Request] --> B{Circuit open?}
B -- Yes --> C[503 Service Unavailable]
B -- No --> D[Execute route]
D --> E{Response 5xx?}
E -- Yes --> F[recordFailure]
E -- No --> G[recordSuccess]
F --> H[Return response]
G --> H
Loading
Register the middleware on your routes:
<?php // routes/api.php use App\Http\Controllers\PaymentController; use Illuminate\Support\Facades\Route; Route::middleware('circuit-breaker:payment-api') ->post('/payments/charge', [PaymentController::class, 'charge']); Route::middleware('circuit-breaker:email-service') ->post('/notifications/send', [NotificationController::class, 'send']);
When the circuit is open the middleware returns a JSON response:
{
"message": "Service unavailable."
}
with HTTP status 503 Service Unavailable.
Artisan Commands
# Check the current state of a service's circuit php artisan circuit-breaker:status payment-api # Force a state override (useful during deploys or incidents) php artisan circuit-breaker:force payment-api open php artisan circuit-breaker:force payment-api closed --ttl=300 # auto-expires in 5 min # Remove a manual override and return to normal state logic php artisan circuit-breaker:clear payment-api
Events
All circuit breaker events are dispatched through Laravel's event system, so you can listen to them like any other Laravel event:
<?php // app/Providers/AppServiceProvider.php namespace App\Providers; use GabrielAnhaia\PhpCircuitBreaker\Event\CircuitOpenedEvent; use GabrielAnhaia\PhpCircuitBreaker\Event\CircuitClosedEvent; use GabrielAnhaia\PhpCircuitBreaker\Event\FailureRecordedEvent; use GabrielAnhaia\PhpCircuitBreaker\Event\SuccessRecordedEvent; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Log; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { public function boot(): void { Event::listen(CircuitOpenedEvent::class, function (CircuitOpenedEvent $event): void { Log::warning("Circuit OPENED for [{$event->getServiceName()}]"); }); Event::listen(CircuitClosedEvent::class, function (CircuitClosedEvent $event): void { Log::info("Circuit CLOSED for [{$event->getServiceName()}]"); }); } }
| Event | Fired when |
|---|---|
FailureRecordedEvent |
A failure is recorded |
SuccessRecordedEvent |
A success is recorded |
CircuitOpenedEvent |
The circuit transitions to OPEN |
CircuitClosedEvent |
The circuit transitions to CLOSED |
CircuitHalfOpenEvent |
The circuit transitions to HALF_OPEN |
Every event exposes getServiceName(): string and getOccurredAt(): DateTimeImmutable.
Manual Override
Force a circuit state for maintenance windows or during an incident:
<?php use GabrielAnhaia\LaravelCircuitBreaker\Facades\CircuitBreaker; use GabrielAnhaia\PhpCircuitBreaker\CircuitState; // Block all traffic to a service (force OPEN) CircuitBreaker::forceState('payment-api', CircuitState::OPEN); // Block for 5 minutes, then automatically return to normal state logic CircuitBreaker::forceState('payment-api', CircuitState::OPEN, ttl: 300); // Remove the override CircuitBreaker::clearOverride('payment-api');
Upgrade from v1
See UPGRADE-2.0.md for step-by-step migration instructions.
Development
composer test # Run PHPUnit (unit + feature) composer phpstan # Static analysis — level max composer cs-check # Code style dry-run composer cs-fix # Auto-fix code style
Support
If you find this package useful, consider supporting it:
License
MIT. See LICENSE for details.
gabrielanhaia/laravel-circuit-breaker 适用场景与选型建议
gabrielanhaia/laravel-circuit-breaker 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 1.97k 次下载、GitHub Stars 达 49, 最近一次更新时间为 2020 年 07 月 06 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「laravel」 「microservices」 「fault-tolerance」 「circuit-breaker」 「resilience」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 gabrielanhaia/laravel-circuit-breaker 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 gabrielanhaia/laravel-circuit-breaker 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 gabrielanhaia/laravel-circuit-breaker 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Light & simple Circuit Breaker for PHP to prevent cascading failures in distributed systems.
The Listener component of the RabbitEvents library.
The Publisher component of the RabbitEvents package.
Laravel common
Laravel support for additional blueprint methods
Laravel comment system
统计信息
- 总下载量: 1.97k
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 49
- 点击次数: 9
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2020-07-06
