Ganesha
:elephant: A Circuit Breaker pattern implementation for PHP applications.
Install / Use
/learn @ackintosh/GaneshaREADME
Ganesha is PHP implementation of Circuit Breaker pattern which has multi strategies to avoid cascading failures and supports various storages to record statistics.
<div align="center">
This is one of the Circuit Breaker implementations in PHP that is actively developed, production-ready, well-tested and well-documented. :muscle: You can easily integrate Ganesha into your existing code base, as Ganesha provides just simple interfaces and Guzzle Middleware behaves transparency.
Table of contents
- Ganesha
- Table of contents
- Are you interested?
- Unveil Ganesha
- Usage
- Strategies
- Adapters
- Customizing storage keys
- Ganesha :heart: Guzzle
- Ganesha :heart: OpenAPI Generator
- Ganesha :heart: Symfony HttpClient
- Companies using Ganesha :rocket:
- The articles/videos Ganesha loves :sparkles: :elephant: :sparkles:
- Run tests
- Requirements
- Build promotion site with Soushi
- Author
Are you interested?
Here is an example which shows you how Ganesha behaves when a failure occurs.
It is easily executable. All you need is Docker.
Unveil Ganesha
# Install Composer
$ curl -sS https://getcomposer.org/installer | php
# Run the Composer command to install the latest version of Ganesha
$ php composer.phar require ackintosh/ganesha
Usage
Ganesha provides following simple interfaces. Each method receives a string (named $service in example) to identify the service. $service will be the service name of the API, the endpoint name, etc. Please remember that Ganesha detects system failure for each $service.
$ganesha->isAvailable($service);
$ganesha->success($service);
$ganesha->failure($service);
// For further details about builder options, please see the `Strategy` section.
$ganesha = Ackintosh\Ganesha\Builder::withRateStrategy()
->adapter(new Ackintosh\Ganesha\Storage\Adapter\Redis($redis))
->failureRateThreshold(50)
->intervalToHalfOpen(10)
->minimumRequests(10)
->timeWindow(30)
->build();
$service = 'external_api';
if (!$ganesha->isAvailable($service)) {
die('external api is not available');
}
try {
echo \Api::send($request)->getBody();
$ganesha->success($service);
} catch (\Api\RequestTimedOutException $e) {
// If an error occurred, it must be recorded as failure.
$ganesha->failure($service);
die($e->getMessage());
}
Three states of circuit breaker
<img src="https://user-images.githubusercontent.com/1885716/53690408-4a7f3d00-3dad-11e9-852c-0e082b7b9636.png" width="500">(martinfowler.com : CircuitBreaker)
Ganesha follows the states and transitions described in the article faithfully. $ganesha->isAvailable() returns true if the circuit states on Closed, otherwise it returns false.
Subscribe to events in ganesha
- When the circuit state transitions to
Openthe eventGanesha::EVENT_TRIPPEDis triggered - When the state back to
Closedthe eventGanesha::EVENT_CALMED_DOWNis triggered
$ganesha->subscribe(function ($event, $service, $message) {
switch ($event) {
case Ganesha::EVENT_TRIPPED:
\YourMonitoringSystem::warn(
"Ganesha has tripped! It seems that a failure has occurred in {$service}. {$message}."
);
break;
case Ganesha::EVENT_CALMED_DOWN:
\YourMonitoringSystem::info(
"The failure in {$service} seems to have calmed down :). {$message}."
);
break;
case Ganesha::EVENT_STORAGE_ERROR:
\YourMonitoringSystem::error($message);
break;
default:
break;
}
});
Disable
If disabled, Ganesha keeps to record success/failure statistics, but Ganesha doesn't trip even if the failure count reached to a threshold.
// Ganesha with Count strategy(threshold `3`).
// $ganesha = Ackintosh\Ganesha\Builder::withCountStrategy() ...
// Disable
Ackintosh\Ganesha::disable();
// Although the failure is recorded to storage,
$ganesha->failure($service);
$ganesha->failure($service);
$ganesha->failure($service);
// Ganesha does not trip and Ganesha::isAvailable() returns true.
var_dump($ganesha->isAvailable($service));
// bool(true)
Reset
Resets the statistics saved in a storage.
$ganesha = Ackintosh\Ganesha\Builder::withRateStrategy()
// ...
->build();
$ganesha->reset();
Strategies
Ganesha has two strategies which avoids cascading failures.
Rate
$ganesha = Ackintosh\Ganesha\Builder::withRateStrategy()
// The interval in time (seconds) that evaluate the thresholds.
->timeWindow(30)
// The failure rate threshold in percentage that changes CircuitBreaker's state to `OPEN`.
->failureRateThreshold(50)
// The minimum number of requests to detect failures.
// Even if `failureRateThreshold` exceeds the threshold,
// CircuitBreaker remains in `CLOSED` if `minimumRequests` is below this threshold.
->minimumRequests(10)
// The interval (seconds) to change CircuitBreaker's state from `OPEN` to `HALF_OPEN`.
->intervalToHalfOpen(5)
// The storage adapter instance to store various statistics to detect failures.
->adapter(new Ackintosh\Ganesha\Storage\Adapter\Memcached($memcached))
->build();
Note about "time window": The Storage Adapter implements either SlidingTimeWindow or TumblingTimeWindow. The difference of the implementation comes from constraints of the storage functionalities.
[SlidingTimeWindow]
- SlidingTimeWindow implements a time period that stretches back in time from the present. For instance, a SlidingTimeWindow of 30 seconds includes any events that have occurred in the past 30 seconds.
- Redis adapter and MongoDB adapter implements SlidingTimeWindow.
The details to help us understand visually is shown below:
(quoted from Introduction to Stream Analytics windowing functions - Microsoft Azure)
[TumblingTimeWindow]
- TumblingTimeWindow implements time segments, which are divided by a value of
timeWindow. - APCu adapter and Memcached adapter implement TumblingTimeWindow.
The details to help us understand visually is shown below:
(quoted from Introduction to Stream Analytics windowing functions - Microsoft Azure)
Count
If you prefer the Count strategy use Builder::withCountStrategy() to build an instance.
$ganesha = Ackintosh\Ganesha\Builder::withCountStrategy()
// The failure count threshold that changes CircuitBreaker's state to `OPEN`.
// The count will be increased if `$ganesha->failure()` is called,
// or will be decreased if `$ganesha->success()` is called.
->failureCountThreshold(100)
// The interval (seconds) to change CircuitBreaker's state from `OPEN` to `HALF_OPEN`.
->intervalToHalfOpen(5)
// The storage adapter instance to store various statistics to detect failures.
->adapter(new Ackintosh\Ganesha\Storage\Adapter\Memcached($memcached))
->build();
Adapters
APCu
The APCu adapter requires the APCu extension.
$adapter = new Ackintosh\Ganesha\Storage\Adapter\Apcu();
$ganesha = Ackintosh\Ganesha\Builder:
Related Skills
node-connect
340.5kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
84.2kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
340.5kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
84.2kCommit, push, and open a PR

