Different Implementation of Circuit Breaker pattern in PHP
About pattern: https://en.wikipedia.org/wiki/Circuit_breaker_design_pattern
- PHP >= 8.0
- Memcached php extension for Memcache storage
- Any PSR-3 logger on your choose.
WARNING!: The project is in the beta stage so please be careful.
TODO:
- Add more Unit tests (in progress)
Add enable/disable logic for Scb(done)- Add Redis storage
- Add Cascading logic to prevent dependant calls
- More examples (in progress)
- Refactoring for Logging
Scb main class is a singleton.
Initializing it you will create a main class for all your circuit breakers. Each item, created by the item($name) method, represents a separate circuit breaker with different storage and configuration.
// Each item should have a unique name.
// Calling method item('xxx') will create a new item
// or return the existing one.
$smartCircuitBreaker->item("call-google-api-service");Scb configuration is a php array. By default, the Scb uses the configuration stored in config.default.php
[
// Enable circuit breaker logic
'enabled' => true,
// default log level
'defaultLogLevel' => 'debug',
// list of items
'items' => [
// The * corresponds to any item, excluding specified as a separate item
'*' => [
// Threshold to open circuit breaker
'numberOfErrorsToOpen' => 5,
// after this amount of seconds, the status will be invalidated during the script init stage.
'ttlForFail' => 60,
// List of timeouts in seconds
'timeoutsToRetry' => [0,1,2,3,4,5,10,15,20,30,45,60],
// Storage type: 'file', 'redis' or 'memcache'
'storage' => 'file',
],
/*
* Example of custom item:
* 'custom-item' => [
* 'numberOfErrorsToOpen' => 12,
'ttlForFail' => 60,
'timeoutsToRetry' => [0,1,2,3,4,5,10],
'storage' => 'file',
* ]
*/
],
// Storages
'storages' => [
// File storage
'file' => [
// Prefix for the file name
'prefix' => 'scb_',
// directory, no trailing slash
'path' => '/tmp',
],
// Memcache storage
'memcache' => [
// Prefix for the key name
'prefix' => 'scb_',
// Memcache server hostname
'host' => 'localhost',
// Memcache server port
'port' => '11211',
// Enable igbinary
'igbinaryEnabled' => false,
],
// Redis storage
'redis' => [
// Prefix for the key name
'prefix' => 'scb_',
],
],
];Other examples can be found under examples directory.
Example 0
// Create an instance
$smartCircuitBreaker = Scb::getInstance();
// If no logger specified, the Smart Circuit Breaker will use the default logger (LogWrapper.php)
// Some code inside the circuit breaker
$smartCircuitBreaker->item("dummy")->execute(function () {
// Call some service, or DB
//throw new \Exception("Dummy exception");
}
});Example 1:
// Create an instance
$smartCircuitBreaker = Scb::getInstance();
// Add logger
$logger = new LogWrapper();
$smartCircuitBreaker->setLogger($logger);
// Put your code inside the circuit breaker
$smartCircuitBreaker->item("dummy")->execute(function () {
// Call some service, or DB
//throw new \Exception("Dummy exception");
}
});Example 2:
// Create an instance
$smartCircuitBreaker = Scb::getInstance();
// Add logger
$logger = new LogWrapper();
$smartCircuitBreaker->setLogger($logger);
// Put your code inside the circuit breaker
$smartCircuitBreaker->item("curl-item")->execute(function() {
$url = "https://www.some-not-existing-url.com/";
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $url);
$res = curl_exec($ch);
if (curl_error($ch)) {
$errorMessage = curl_error($ch);
curl_close($ch);
throw new \Exception($errorMessage);
}
curl_close($ch);
echo $res;
});
For now only 2 types of storages are supported:
- File storage
- Memcache storage
If you have only one PHP server, I would recommend to use the File Storage. In this case your code will be totally independant on any external services and network issues. Everything needed for the Circuit Breaker to work will be stored locally on the file system.
In the case of 2 or more PHP servers, Memcache storage is probably the best solution. You can still use the File Storage if you wish, but in this case, each of your PHP servers will have completely separate storage for the circuit breaker cache. It's not that bad and can even provide some of the benefits over a centralized repository, but sometimes it's better to have one place where you can control your Circuit Breaker cache.