leocarmo / circuit-breaker-php
Circuit Breaker for PHP
Installs: 297 656
Dependents: 4
Suggesters: 0
Security: 0
Stars: 282
Watchers: 4
Forks: 25
Open Issues: 1
Requires
- php: ^8.0
- psr/http-message: ^1.0
Requires (Dev)
- guzzlehttp/guzzle: ^7.0
- phpunit/php-code-coverage: ^9.2
- phpunit/phpunit: ^9
- swoole/ide-helper: dev-master
- symfony/var-dumper: ^5.2
Suggests
- ext-redis: Required to use Redis Adapter.
- ext-swoole: Required to use Swoole Table Adapter.
- guzzlehttp/guzzle: Allows the usage of the GuzzleMiddleware
README
For more information about this pattern see this.
Starting with composer
composer require leocarmo/circuit-breaker-php
Adapters
Redis Adapter
The first argument is a redis connection, the second is your product name, for redis namespace avoid key conflicts with another product using the same redis.
use LeoCarmo\CircuitBreaker\CircuitBreaker; use LeoCarmo\CircuitBreaker\Adapters\RedisAdapter; // Connect to redis $redis = new \Redis(); $redis->connect('localhost', 6379); $adapter = new RedisAdapter($redis, 'my-product'); // Set redis adapter for CB $circuit = new CircuitBreaker($adapter, 'my-service');
See this for full example
Redis Cluster Adapter
Without use of multi
command.
The first argument is a redis connection, the second is your product name, for redis namespace avoid key conflicts with another product using the same redis.
use LeoCarmo\CircuitBreaker\CircuitBreaker; use LeoCarmo\CircuitBreaker\Adapters\RedisClusterAdapter; // Connect to redis $redis = new \Redis(); $redis->connect('localhost', 6379); $adapter = new RedisClusterAdapter($redis, 'my-product'); // Set redis adapter for CB $circuit = new CircuitBreaker($adapter, 'my-service');
See this for full example
SwooleTable Adapter
use LeoCarmo\CircuitBreaker\CircuitBreaker; $circuit = new CircuitBreaker(new SwooleTableAdapter(), 'my-service');
Guzzle Middleware
use GuzzleHttp\Client; use GuzzleHttp\HandlerStack; use LeoCarmo\CircuitBreaker\GuzzleMiddleware; $handler = new GuzzleMiddleware($circuit); $handlers = HandlerStack::create(); $handlers->push($handler); $client = new Client(['handler' => $handlers]); $response = $client->get('leocarmo.dev');
Important: all status code between 200 and 299 will be recorded as a success, and other status will be recorded as a failure.
See this for full example
Customize success status code
If you need to specify a custom status code that is not a failure, you can use:
$handler = new GuzzleMiddleware($circuit); $handler->setCustomSuccessCodes([400]);
Important: this configuration will record a success when a status code 400
is returned
See this for full example
Ignore status code
If you want to ignore the status code returned and not record a success or failure, use this:
$handler = new GuzzleMiddleware($circuit); $handler->setCustomIgnoreCodes([412]);
Important
To use Customize success status code
or Ignore status code
you must set the Guzzle client config http_errors = false
because the Guzzle Client throws a ClientException
or ServerException
when the status code is not in range >200 && <300
.
Set circuit break settings
This is not required, default values will be set
$circuit->setSettings([ 'timeWindow' => 60, // Time for an open circuit (seconds) 'failureRateThreshold' => 50, // Fail rate for open the circuit 'intervalToHalfOpen' => 30, // Half open time (seconds) ]);
Check if circuit is available (closed)
Each check is for a specific service. So you can have multiple services in the same application, and when one circuit is open, the other works normally.
// Check circuit status for service if (! $circuit->isAvailable()) { die('Circuit is not available!'); }
Record success and failure
// Usage example for success and failure try { myService(); $circuit->success(); } catch (RuntimeException $e) { // If an error occurred, it must be recorded as failure. $circuit->failure(); }
Development
Setup
make setup
Tests
make test