What is php-circuit-breaker-bundle
, (*1)
, (*2)
php-circuit-breaker-bundle is a Symfony 2 bundle, providing easy integration of php-circuit-breaker component., (*3)
php-circuit-breaker is the core package providing a generic
PHP implementation of circuit breaker pattern. This bundle wraps it up
and makes easier to use with Symfony 2 framework.
Bundle uses service.xml to configure default services. It also integrates with Doctrine/Cache to allow you to use any
cache backend (in case you were already using Doctrine/Cache)., (*4)
Motivation & Benefits
- Easy use of circuit breaker withing Symfony 2 applications.
Installation
Since Symfony 2 uses Composer, all you have to do is add a require dependency to your composer.json, (*5)
"require": {
"ejsmont-artur/php-circuit-breaker-bundle": "0.1.*"
},
Then you can override defaults of threshold and timeout in your application services.yaml, (*6)
parameters:
# Allowed amount of failures before marking service as unavailable
ejsmont_circuit_breaker.threshold: 3
# how many seconds should we wait before allowing a single request
ejsmont_circuit_breaker.retry_timeout: 5
After that you should update composer dependencies and you are good to go., (*7)
Examples
Below you can see a few ways of obtaining instances of circuit breaker component. You can also see how to use it once
you get an instance. For more documentation please see php-circuit-breaker page., (*8)
Example 1 - default APC storage
This is the simplest example as you use defaults for all settings and default APC storage.
Circuit breaker status information will be serialised into APC cache., (*9)
$circuitBreaker = $this->get('apcCircuitBreaker');
Yes, that is it. You can use predefined service called apcCircuitBreaker and you do not need any settings.
It will use static factory and keep returning the same instance during script run., (*10)
Example 2 - configuration via dependency injection
Beside of "apcCircuitBreaker" service that uses APC you can use "circuitBreaker" service which is configurable and
allows you to inject any doctrine cache instance., (*11)
In the example below i use "circuitBreakerCacheBackend" service to override the default behaviour of "circuitBreaker"
service. Here i am using memcached but it could be any doctrine cache instance. This service affects behaviour of
"circuitBreaker" only, "apcCircuitBreaker" service uses its own APC cache instance., (*12)
Configure as needed in service.yaml of your app:, (*13)
services:
circuitBreakerCacheBackend:
class: Doctrine\Common\Cache\MemcachedCache
calls:
- [setMemcached, ["@memcachedInstance"]]
memcachedInstance:
class: Memcached
calls:
- [addServer, ['127.0.0.1', 11211, 1]]
Then in your code you can use the configurable doctrine cache instance like below:, (*14)
$circuitBreaker = $this->get('circuitBreaker');
Example 3 - manual composition
If you wanted to do it for some reason you can also create instance of circuit breaker by hand.
In this example we use Doctrine\Cache adapter so all you need to provide is the cache instance.
In this case, just to mix it up, we have decided to use file cache., (*15)
$fileCache = new \Doctrine\Common\Cache\FilesystemCache('/tmp/cache/', '.cache');
$circuitBreaker = Factory::getDoctrineCacheInstance($fileCache);
Example of how to use an instance
See more details of Circuit Breaker pattern on php-circuit-breaker
github page and my blog posts on circuit breaker, (*16)
In short, once you get instance of circuit breaker, you can ask it if particular service is available or not.
Circuit breaker will check it's status metrics and give you response based on its previous records.
After a successful connection to the service you should tell Circuit Breaker that it went ok. In case of service
failure or timeout, you should report failure to circuit breaker., (*17)
This way Circuit breaker "learns" what is the current status of each service (names are arbitrary strings).
You can define threshold and retry timeout to allow single request from time to time in case service got fixed., (*18)
if ($circuitBreaker->isAvailable("UserProfileService1")) {
try{
// do something useful with the service
$circuitBreaker->reportSuccess('UserProfileService1');
}catch(ServiceCallFailedServiceDown $e){
// if service is down report it back to circuit breaker
$circuitBreaker->reportFailure('UserProfileService1');
// handle as temporarily unavailable (or remove some features)
}
}else{
// handle as temporarily unavailable (or remove some features)
}
Running tests
- Tests are run via PHPUnit It is assumed to be installed via PEAR.
- Tests can be ran using phpunit alone or via ant build targets.
- Tests require all dependencies to be present as bundle is expected to by used only in symfony2 apps.
- The "ci" target generate code coverage repor, "phpunit" target does not.
If you dont have composer, get it and download dependencies (creates /vendor folder), (*19)
curl -s http://getcomposer.org/installer | php
php composer.phar update
You can run all tests using ant:, (*20)
ant phpunit
You can run tests, generate coverage and docs:, (*21)
ant ci
You can run selected test case by running:, (*22)
cd tests
phpunit Unit/Ejsmont/CircuitBreakerBundle/Storage/DoctrineCacheAdapterTest.php
Author
- Artur Esjmont (https://github.com/ejsmont-artur) via http://artur.ejsmont.org