1. Go to this page and download the library: Download ackintosh/ganesha library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
// 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());
}
$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;
}
});
// 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)
$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();
$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();
$redis = new \Redis();
$redis->connect('localhost');
$adapter = new Ackintosh\Ganesha\Storage\Adapter\Redis($redis);
$ganesha = Ackintosh\Ganesha\Builder::withRateStrategy()
->adapter($adapter)
// ... (omitted) ...
->build();
$memcached = new \Memcached();
$memcached->addServer('localhost', 11211);
$adapter = new Ackintosh\Ganesha\Storage\Adapter\Memcached($memcached);
$ganesha = Ackintosh\Ganesha\Builder::withRateStrategy()
->adapter($adapter)
// ... (omitted) ...
->build();
$manager = new \MongoDB\Driver\Manager('mongodb://localhost:27017/');
$adapter = new Ackintosh\Ganesha\Storage\Adapter\MongoDB($manager, 'dbName', 'collectionName');
$ganesha = Ackintosh\Ganesha\Builder::withRateStrategy()
->adapter($adapter)
// ... (omitted) ...
->build();
class YourStorageKeys implements StorageKeysInterface
{
public function prefix()
{
return 'your_prefix_';
}
// ... (omitted) ...
}
$ganesha = Ackintosh\Ganesha\Builder::withRateStrategy()
// The keys which will stored by Ganesha to the storage you specified via `adapter`
// will be prefixed with `your_prefix_`.
->storageKeys(new YourStorageKeys())
// ... (omitted) ...
->build();
use Ackintosh\Ganesha\Builder;
use Ackintosh\Ganesha\GuzzleMiddleware;
use Ackintosh\Ganesha\Exception\RejectedException;
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
$ganesha = Builder::withRateStrategy()
->timeWindow(30)
->failureRateThreshold(50)
->minimumRequests(10)
->intervalToHalfOpen(5)
->adapter($adapter)
->build();
$middleware = new GuzzleMiddleware($ganesha);
$handlers = HandlerStack::create();
$handlers->push($middleware);
$client = new Client(['handler' => $handlers]);
try {
$client->get('http://api.example.com/awesome_resource');
} catch (RejectedException $e) {
// If the circuit breaker is open, RejectedException will be thrown.
}
// In the example above, `api.example.com` is used as `$service`.
$client->get('http://api.example.com/awesome_resource');
// via constructor argument
$client = new Client([
'handler' => $handlers,
// 'ganesha.service_name' is defined as ServiceNameExtractor::OPTION_KEY
'ganesha.service_name' => 'specified_service_name',
]);
// via request method argument
$client->get(
'http://api.example.com/awesome_resource',
[
'ganesha.service_name' => 'specified_service_name',
]
);
// via request header
$request = new Request(
'GET',
'http://api.example.com/awesome_resource',
[
// 'X-Ganesha-Service-Name' is defined as ServiceNameExtractor::HEADER_NAME
'X-Ganesha-Service-Name' => 'specified_service_name'
]
);
$client->send($request);
use Ackintosh\Ganesha\GuzzleMiddleware\ServiceNameExtractorInterface;
use Psr\Http\Message\RequestInterface;
class SampleExtractor implements ServiceNameExtractorInterface
{
/**
* @override
*/
public function extract(RequestInterface $request, array $requestOptions)
{
// We treat the combination of host name and HTTP method name as $service.
return $request->getUri()->getHost() . '_' . $request->getMethod();
}
}
// ---
$ganesha = Builder::withRateStrategy()
// ...
->build();
$middleware = new GuzzleMiddleware(
$ganesha,
// Pass the extractor as an argument of GuzzleMiddleware constructor.
new SampleExtractor()
);
use Ackintosh\Ganesha\GuzzleMiddleware\FailureDetectorInterface;
use Psr\Http\Message\ResponseInterface;
class HttpStatusFailureDetector implements FailureDetectorInterface
{
public function isFailureResponse(ResponseInterface $response) : bool
{
return in_array($response->getStatusCode(), [503, 504], true);
}
}
// ---
$ganesha = Builder::withRateStrategy()
// ...
->build();
$middleware = new GuzzleMiddleware(
$ganesha,
// Pass the failure detector to the GuzzleMiddleware constructor.
failureDetector: new HttpStatusFailureDetector()
);
// For details on how to build middleware please see https://github.com/ackintosh/ganesha#ganesha-heart-guzzle
$middleware = new GuzzleMiddleware($ganesha);
// Set the middleware to HTTP client.
$handlers = HandlerStack::create();
$handlers->push($middleware);
$client = new Client(['handler' => $handlers]);
// Just pass the HTTP client to the constructor of API class.
$api = new PetApi($client);
try {
// Ganesha is working in the shadows! The result of api call is monitored by Ganesha.
$api->getPetById(123);
} catch (RejectedException $e) {
awesomeErrorHandling($e);
}
use Ackintosh\Ganesha\Builder;
use Ackintosh\Ganesha\GaneshaHttpClient;
use Ackintosh\Ganesha\Exception\RejectedException;
$ganesha = Builder::withRateStrategy()
->timeWindow(30)
->failureRateThreshold(50)
->minimumRequests(10)
->intervalToHalfOpen(5)
->adapter($adapter)
->build();
$client = HttpClient::create();
$ganeshaClient = new GaneshaHttpClient($client, $ganesha);
try {
$ganeshaClient->request('GET', 'http://api.example.com/awesome_resource');
} catch (RejectedException $e) {
// If the circuit breaker is open, RejectedException will be thrown.
}
// In the example above, `api.example.com` is used as `$service`.
$ganeshaClient->request('GET', 'http://api.example.com/awesome_resource');
// via constructor argument
$ganeshaClient = new GaneshaHttpClient($client, $ganesha, [
// 'ganesha.service_name' is defined as ServiceNameExtractor::OPTION_KEY
'ganesha.service_name' => 'specified_service_name',
]);
// via request method argument
$ganeshaClient->request(
'GET',
'http://api.example.com/awesome_resource',
[
'ganesha.service_name' => 'specified_service_name',
]
);
// via request header
$ganeshaClient->request('GET', '', ['headers' => [
// 'X-Ganesha-Service-Name' is defined as ServiceNameExtractor::HEADER_NAME
'X-Ganesha-Service-Name' => 'specified_service_name'
]]);
use Ackintosh\Ganesha\HttpClient\HostTrait;
use Ackintosh\Ganesha\HttpClient\ServiceNameExtractorInterface;
final class SampleExtractor implements ServiceNameExtractorInterface
{
use HostTrait;
/**
* @override
*/
public function extract(string $method, string $url, array $requestOptions): string
{
// We treat the combination of host name and HTTP method name as $service.
return self::extractHostFromUrl($url) . '_' . $method;
}
}
// ---
$ganesha = Builder::withRateStrategy()
// ...
->build();
$ganeshaClient = new GaneshaHttpClient(
$client,
$ganesha,
// Pass the extractor as an argument of GaneshaHttpClient constructor.
new SampleExtractor()
);
// via constructor argument
$ganeshaClient = new GaneshaHttpClient(
$client, $ganesha, null,
new RestFailureDetector([503])
);
// via request method argument
$ganeshaClient->request(
'GET',
'http://api.example.com/awesome_resource',
[
// 'ganesha.failure_status_codes' is defined as RestFailureDetector::OPTION_KEY
'ganesha.failure_status_codes' => [503],
]
);
use Ackintosh\Ganesha\HttpClient\FailureDetectorInterface;
use Symfony\Contracts\HttpClient\Exception\ExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
final class SampleFailureDetector implements FailureDetectorInterface
{
/**
* @override
*/
public function isFailureResponse(ResponseInterface $response, array $requestOptions): bool
{
try {
$jsonData = $response->toArray();
} catch (ExceptionInterface $e) {
return true;
}
// Server is not RestFull and always returns HTTP 200 Status Code, but set an error flag in the JSON payload.
return true === ($jsonData['error'] ?? false);
}
/**
* @override
*/
public function getOptionKeys(): array
{
// No option is defined for this implementation
return [];
}
}
// ---
$ganesha = Builder::withRateStrategy()
// ...
->build();
$ganeshaClient = new GaneshaHttpClient(
$client,
$ganesha,
null,
// Pass the failure detector as an argument of GaneshaHttpClient constructor.
new SampleFailureDetector()
);
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.