https://github.com/francescomalatesta/laravel-circuit-breaker
An implementation of the circuit breaker pattern for Laravel 5.6
https://github.com/francescomalatesta/laravel-circuit-breaker
circuit-breaker laravel laravel5 package
Last synced: 8 months ago
JSON representation
An implementation of the circuit breaker pattern for Laravel 5.6
- Host: GitHub
- URL: https://github.com/francescomalatesta/laravel-circuit-breaker
- Owner: francescomalatesta
- License: mit
- Created: 2018-04-18T07:37:09.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2020-06-02T20:06:47.000Z (over 5 years ago)
- Last Synced: 2025-02-01T04:31:42.465Z (9 months ago)
- Topics: circuit-breaker, laravel, laravel5, package
- Language: PHP
- Homepage: http://francesco.codes
- Size: 38.1 KB
- Stars: 28
- Watchers: 2
- Forks: 7
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE.md
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# Laravel Circuit Breaker
An implementation of the Circuit Breaker pattern for Laravel Framework 5.6.
[![Latest Version on Packagist][ico-version]][link-packagist]
[![Software License][ico-license]](LICENSE.md)
[![Build Status][ico-travis]][link-travis]
[![Quality Score][ico-code-quality]][link-code-quality]
[](https://styleci.io/repos/130022855)If you need an easy to use implementation of the [circuit breaker pattern](https://martinfowler.com/bliki/CircuitBreaker.html) for your Laravel application, you're in the right place.
**Note:** this package is compatible with Laravel 5.6. Other/previous versions are not tested yet.
## Install
You can use Composer to install the package for your project.
``` bash
$ composer require francescomalatesta/laravel-circuit-breaker
```Don't worry about service providers and façades: Laravel can auto discover the package without doing nothing!
Just remember to **publish the config file** with
```php
php artisan vendor:publish
```## Usage
You will always use a single class (`CircuitBreaker` façade or `CircuitBreakerManager` class if you want to inject it) to work with this package.
Here's the methods reference:
### isAvailable(string $identifier) : bool
Returns `true` if the `$identifier` service is currently available. Returns `false` otherwise.
**Note:** you can use whatever you want as identifier. I like to use the `MyClass::class` name when possible.
### reportFailure(string $identifier) : void
Reports a failed attempt for the `$identifier` service. Take a look at the Configuration section below to know how attempts and failure times are managed.
### reportSuccess(string $identifier) : void
Reports a successful attempt for the `$identifier` service. You can use it to mark a service as available and remove the "failed" status from it.
## Configuration
### Defaults
By editing the `config/circuit_breaker.php` config file contents you will able to tweak the circuit breaker in a way that is more suitable for your needs.
You have three values under the `default` item:
```php
[
'attempts_threshold' => 3,
'attempts_ttl' => 1,
'failure_ttl' => 5
],
// ...
];
```- **attempts_threshold**: use it to specify how many attempts you have to make before declaring a service "failed" - default: 3;
- **attempts_ttl**: use to specify the time (in minutes) window in which the attempts are made before declaring a service "failed" - default: 1;
- **failure_ttl**: once a service is marked as "failed", it will remain in this status for this number of minutes - default: 5;For a better understanding: by default, 3 failed attempts in 1 minute will result in a "failed" service for 5 minutes.
### Service Map
Tweaking the config file is cool, but what if I need to have specific ttl and attempts count for a specific service? No problem: the `services` option is here to help.
As you can see in the `config/circuit_breaker.php` config file, you also have a `services` item. You can specify settings for a single service here. Here's an example:
```php
[
'attempts_threshold' => 3,
'attempts_ttl' => 1,
'failure_ttl' => 5
],
'services' => [
'my_special_service_identifier' => [
'attempts_threshold' => 2,
'attempts_ttl' => 1,
'failure_ttl' => 10
]
]
];
```Then, when you will call `CircuitBreaker::reportFailure('my_special_service_identifier')`, the circuit breaker will recognize the "special" service and use specific configuration settings, TTLs and attempts count.
**Protip:** you can also *overwrite* a single settings for a service in the `service` array. The others are going to be merged with the defaults.
## Usage Example
Let's assume we have a payments gateway integration for our application. We will call this class `PaymentsGateway`.
Now, let's also assume this is a third party service: sometimes it could be down for a while. However, we don't want to stop our users from buying something, so if the `PaymentsGateway` service is not available we want to redirect orders to a fallback service named `DelayedPaymentsGateway` that will simply "queue" delayed orders to process them in the future.
Let's stub this process in the following `BuyArticleOperation` class.
```php
paymentsGateway->attempt($orderId);
} catch (PaymentsGatewayException $e) {
// something went wrong, let's switch the payment
// to the "delayed" queue system
$this->delayedPaymentsGateway->queue($orderId);
}
}
}
```That's great! Now we are 100% sure that our payments are going to be processed. Sometimes that's not enough.
You know, maybe the `PaymentsGateway` takes at least 5 seconds for a single attempt, and your application receives hundreds of orders every minute. Is it really helpful to repeatedly call the `PaymentsGateway` even if we "know" it's not working after the first attempt?
Well, this is how you can write your code with this circuit breaker.
```php
paymentsGateway->attempt($orderId);
} catch (PaymentsGatewayException $e) {
// something went wrong, let's switch the payment
// to the "delayed" queue system and report that
// the default gateway is not working!
$this->delayedPaymentsGateway->queue($orderId);
CircuitBreaker::reportFailure(PaymentsGateway::class);
}
// there's nothing we can do here anymore
return;
}
// we already know that the service is disabled, so we
// can queue the payment process on the delayed queue
// directly, without letting our users wait more
$this->delayedPaymentsGateway->queue($orderId);
}
}
```Let's assume we are processing 100 orders (on different processes) in 10 seconds.
* for the first order we ask the `PaymentsGateway` to handle that, but something goes wrong;
* we queue the payment on the `DelayedPaymentsGateway` and we report a failure to the `CircuitBreaker`;
* the same goes for the 2nd and 3rd orders;
* after the third order is processed, the `CircuitBreaker` decides that after 3 attempts (and in less than 1 minute) the `PaymentsGateway` can be declared "failed" and we can use directly our `DelayedPaymentsGateway` fallback for a while (5 minutes);
* the remaining 97 orders are queued and processed successfully, without wasting time (97 * 5 = 485 processing seconds) on a service we are quite sure that will not work;Cool, huh? :)
## Testing
You can easily execute tests with
``` bash
$ vendor/bin/phpunit
```## Coming Soon
* exponential backoff for failure TTLs;
* set TTLs less than 1 minute;
* make underlying store implementation customizable;## Contributing
Please see [CONTRIBUTING](CONTRIBUTING.md) and [CODE_OF_CONDUCT](CODE_OF_CONDUCT.md) for details.
## Security
If you discover any security related issues, please email francescomalatesta@live.it instead of using the issue tracker.
## Credits
- [Francesco Malatesta][link-author]
- [All Contributors][link-contributors]## License
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
[ico-version]: https://img.shields.io/packagist/v/francescomalatesta/laravel-circuit-breaker.svg?style=flat-square
[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square
[ico-travis]: https://img.shields.io/travis/francescomalatesta/laravel-circuit-breaker/master.svg?style=flat-square
[ico-code-quality]: https://img.shields.io/scrutinizer/g/francescomalatesta/laravel-circuit-breaker.svg?style=flat-square[link-packagist]: https://packagist.org/packages/francescomalatesta/laravel-circuit-breaker
[link-travis]: https://travis-ci.org/francescomalatesta/laravel-circuit-breaker
[link-scrutinizer]: https://scrutinizer-ci.com/g/francescomalatesta/laravel-circuit-breaker/code-structure
[link-code-quality]: https://scrutinizer-ci.com/g/francescomalatesta/laravel-circuit-breaker
[link-downloads]: https://packagist.org/packages/francescomalatesta/laravel-circuit-breaker
[link-author]: https://github.com/francescomalatesta
[link-contributors]: ../../contributors