SkillAgentSearch skills...

Ganesha

:elephant: A Circuit Breaker pattern implementation for PHP applications.

Install / Use

/learn @ackintosh/Ganesha

README

<h1 align="center">Ganesha</h1>

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">

ganesha

Latest Stable Version Tests Coverage Status Scrutinizer Code Quality Minimum PHP Version

</div>

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

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 Open the event Ganesha::EVENT_TRIPPED is triggered
  • When the state back to Closed the event Ganesha::EVENT_CALMED_DOWN is 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)

<img height="350" title="slidingtimewindow" src="https://s3-ap-northeast-1.amazonaws.com/ackintosh.github.io/timewindow/sliding-window.png">

[TumblingTimeWindow]

The details to help us understand visually is shown below:
(quoted from Introduction to Stream Analytics windowing functions - Microsoft Azure)

<img height="350" title="tumblingtimewindow" src="https://s3-ap-northeast-1.amazonaws.com/ackintosh.github.io/timewindow/tumbling-window.png">

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

View on GitHub
GitHub Stars661
CategoryDevelopment
Updated12d ago
Forks46

Languages

PHP

Security Score

100/100

Audited on Mar 17, 2026

No findings