1. Go to this page and download the library: Download farzai/breaker 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/ */
use Farzai\Breaker\Breaker;
// Configure different services with different thresholds
Breaker::configure('critical-service', [
'failure_threshold' => 2,
'timeout' => 120,
]);
Breaker::configure('non-critical-service', [
'failure_threshold' => 10,
'timeout' => 30,
]);
// Use pre-configured services
$result = Breaker::protect('critical-service', fn() => callCriticalApi());
// Get health for all services
$reports = Breaker::healthReport();
foreach ($reports as $service => $health) {
echo "{$service}: {$health->status->value}\n";
}
// Get health for specific service
$health = Breaker::healthReport('api-service');
echo "Status: {$health->status->value}\n";
echo "Failures: {$health->failureCount}/{$health->failureThreshold}\n";
use Farzai\Breaker\BreakerManager;
class ApiClient
{
public function __construct(private BreakerManager $breaker) {}
public function fetchData(): array
{
return $this->breaker->protect(
'api-service',
fn() => $this->callApi(),
fallback: fn($e) => $this->getCached()
);
}
}
// In your DI container
$manager = new BreakerManager();
$apiClient = new ApiClient($manager);
use Farzai\Breaker\Breaker;
use Farzai\Breaker\Events\CircuitStateChangedEvent;
use Farzai\Breaker\Events\CircuitOpenedEvent;
use Farzai\Breaker\Events\CallSucceededEvent;
use Farzai\Breaker\Events\CallFailedEvent;
// Get the managed instance to add listeners
$breaker = Breaker::instance('api-service');
// Listen to state transitions with typed event objects
$breaker->onStateChange(function (CircuitStateChangedEvent $event) {
echo sprintf(
"Circuit state changed from %s to %s for service %s",
$event->getPreviousState(),
$event->getNewState(),
$event->getServiceKey()
);
});
// Listen to specific state transitions
$breaker->onOpen(function (CircuitOpenedEvent $event) {
// Circuit opened - notify administrators with rich context
sendAlertToAdmin([
'service' => $event->getServiceKey(),
'failure_count' => $event->getFailureCount(),
'failure_threshold' => $event->getFailureThreshold(),
'timeout' => $event->getTimeout(),
'half_open_at' => date('Y-m-d H:i:s', $event->getHalfOpenTimestamp()),
]);
});
$breaker->onHalfOpen(function (CircuitHalfOpenedEvent $event) {
logEvent("Testing if service is back online", [
'success_threshold' => $event->getSuccessThreshold(),
]);
});
$breaker->onClose(function (CircuitClosedEvent $event) {
// Check if this is a recovery or initial close
$message = $event->isRecovery()
? 'Service recovered successfully'
: 'Service initialized';
sendStatusUpdate($message);
});
// Listen to call success with execution metrics
$breaker->onSuccess(function (CallSucceededEvent $event) {
incrementMetric('service.success', [
'execution_time' => $event->getExecutionTime(), // milliseconds
'state' => $event->getCurrentState(),
'result' => $event->getResult(),
]);
});
// Listen to failures with detailed error info
$breaker->onFailure(function (CallFailedEvent $event) {
if ($event->willTriggerOpen()) {
sendCriticalAlert('Circuit about to open!');
}
logError($event->getExceptionMessage(), [
'exception_class' => $event->getExceptionClass(),
'execution_time' => $event->getExecutionTime(),
'failure_count' => $event->getFailureCount(),
'threshold' => $event->getFailureThreshold(),
]);
});
// Remove a listener when no longer needed
$listenerId = $breaker->onSuccess(function ($event) { /* ... */ });
$breaker->removeListener($listenerId);
// High priority listener executes first
$breaker->onFailure(function (CallFailedEvent $event) {
criticalErrorHandler($event);
}, priority: 100);
// Normal priority listener
$breaker->onFailure(function (CallFailedEvent $event) {
logError($event);
}, priority: 0);
// Low priority listener executes last
$breaker->onFailure(function (CallFailedEvent $event) {
sendMetrics($event);
}, priority: -10);
$breaker->onFailure(function (CallFailedEvent $event) {
if ($event->willTriggerOpen()) {
handleCriticalFailure($event);
// Stop other failure listeners from executing
$event->stopPropagation();
}
});
use Farzai\Breaker\Events\EventSubscriberInterface;
use Farzai\Breaker\Events\CallSucceededEvent;
use Farzai\Breaker\Events\CallFailedEvent;
use Farzai\Breaker\Events\CircuitOpenedEvent;
class MetricsCollectorSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
CallSucceededEvent::class => 'onSuccess',
CallFailedEvent::class => ['method' => 'onFailure', 'priority' => 100],
CircuitOpenedEvent::class => 'onOpen',
];
}
public function onSuccess(CallSucceededEvent $event): void
{
$this->metrics->increment('circuit.success', [
'service' => $event->getServiceKey(),
'execution_time' => $event->getExecutionTime(),
]);
}
public function onFailure(CallFailedEvent $event): void
{
$this->metrics->increment('circuit.failure', [
'service' => $event->getServiceKey(),
'exception' => $event->getExceptionClass(),
]);
}
public function onOpen(CircuitOpenedEvent $event): void
{
$this->metrics->increment('circuit.opened', [
'service' => $event->getServiceKey(),
]);
}
}
// Add the subscriber to your circuit breaker
$breaker->addSubscriber(new MetricsCollectorSubscriber($metrics));
use Farzai\Breaker\Events\Subscribers\LoggingSubscriber;
use Psr\Log\LogLevel;
// With default log level (INFO)
$breaker->addSubscriber(new LoggingSubscriber($logger));
// With custom log level
$breaker->addSubscriber(new LoggingSubscriber($logger, LogLevel::WARNING));
use Farzai\Breaker\Events\Subscribers\MetricsSubscriber;
use Farzai\Breaker\Metrics\InMemoryMetricsCollector;
$metricsCollector = new InMemoryMetricsCollector();
$breaker->addSubscriber(new MetricsSubscriber($metricsCollector));
// Later, retrieve collected metrics
$metrics = $metricsCollector->getMetrics();
echo "Success rate: {$metrics->getSuccessRate()}%";
use Farzai\Breaker\Breaker;
use Farzai\Breaker\Storage\StorageFactory;
// Create file storage repository
$repository = StorageFactory::createRepository(
StorageFactory::file(__DIR__ . '/storage/circuit-breaker')
);
// Set as default for all circuit breakers
Breaker::setDefaultRepository($repository);
// Now all protected calls use persistent storage
$result = Breaker::protect('api-service', fn() => callApi());
use Farzai\Breaker\Breaker;
// Configure each service based on criticality
Breaker::configure('user-service', [
'failure_threshold' => 5,
'timeout' => 30,
]);
Breaker::configure('payment-service', [
'failure_threshold' => 2, // Critical - fail fast
'timeout' => 60,
]);
Breaker::configure('notification-service', [
'failure_threshold' => 10, // Non-critical - more lenient
'timeout' => 15,
]);
// Critical service with stricter thresholds
Breaker::configure('critical-service', [
'failure_threshold' => 2, // Open after just 2 failures
'timeout' => 60, // Wait longer before testing again
'success_threshold' => 3, // Require more successes to restore
]);
// Non-critical service with more lenient settings
Breaker::configure('non-critical-service', [
'failure_threshold' => 10, // Allow more failures
'timeout' => 15, // Test again quickly
'success_threshold' => 1, // Close after first success
]);
use Farzai\Breaker\Events\Subscribers\LoggingSubscriber;
// Use built-in logging subscriber for automatic logging
$breaker->addSubscriber(new LoggingSubscriber($logger));
// Or create custom monitoring with event listeners
$breaker->onStateChange(function (CircuitStateChangedEvent $event) use ($logger) {
$logger->info("Circuit '{$event->getServiceKey()}' changed", [
'previous_state' => $event->getPreviousState(),
'new_state' => $event->getNewState(),
'timestamp' => $event->getTimestamp(),
]);
});
// Alert on circuit open with rich context
$breaker->onOpen(function (CircuitOpenedEvent $event) use ($alertService) {
$alertService->sendAlert([
'title' => "Circuit breaker opened",
'service' => $event->getServiceKey(),
'failures' => "{$event->getFailureCount()}/{$event->getFailureThreshold()}",
'retry_at' => date('Y-m-d H:i:s', $event->getHalfOpenTimestamp()),
'severity' => 'critical',
]);
});
// Track execution metrics
$breaker->onSuccess(function (CallSucceededEvent $event) use ($metrics) {
$metrics->histogram('circuit.execution_time', $event->getExecutionTime(), [
'service' => $event->getServiceKey(),
'state' => $event->getCurrentState(),
]);
});
use Farzai\Breaker\BreakerManager;
use Farzai\Breaker\Events\CallSucceededEvent;
use Farzai\Breaker\Events\CircuitOpenedEvent;
use Farzai\Breaker\Events\Subscribers\LoggingSubscriber;
class ApiClient
{
private HttpClientInterface $httpClient;
private BreakerManager $breaker;
private CacheInterface $cache;
private LoggerInterface $logger;
public function __construct(
HttpClientInterface $httpClient,
BreakerManager $breaker,
CacheInterface $cache,
LoggerInterface $logger
) {
$this->httpClient = $httpClient;
$this->breaker = $breaker;
$this->cache = $cache;
$this->logger = $logger;
// Set up monitoring with subscribers
$this->setupMonitoring();
}
public function fetchData($id)
{
return $this->breaker->protect(
'api-client',
function () use ($id) {
$response = $this->httpClient->get("/data/{$id}");
// Cache successful responses
$this->cache->set("data_{$id}", $response, 3600);
return $response;
},
fallback: fn($exception) => $this->cache->get("data_{$id}")
);
}
private function setupMonitoring(): void
{
$circuitBreaker = $this->breaker->instance('api-client');
// Add built-in logging subscriber
$circuitBreaker->addSubscriber(
new LoggingSubscriber($this->logger)
);
// Add custom event listeners for specific actions
$circuitBreaker->onSuccess(function (CallSucceededEvent $event) {
if ($event->getExecutionTime() > 1000) {
$this->logger->warning('Slow API response detected', [
'execution_time' => $event->getExecutionTime(),
'threshold' => 1000,
]);
}
});
$circuitBreaker->onOpen(function (CircuitOpenedEvent $event) {
// Send alert to monitoring system
$this->sendAlert('API Circuit Opened', [
'failures' => $event->getFailureCount(),
'retry_at' => date('Y-m-d H:i:s', $event->getHalfOpenTimestamp()),
]);
});
}
private function sendAlert(string $title, array $context): void
{
// Implementation for sending alerts
}
}
use Farzai\Breaker\Events\EventDispatcher;
$breaker->getEventDispatcher()->setErrorHandlingStrategy(
EventDispatcher::ERROR_STRATEGY_SILENT // Log errors and continue (default)
// EventDispatcher::ERROR_STRATEGY_COLLECT // Collect errors for later inspection
// EventDispatcher::ERROR_STRATEGY_STOP // Stop on first error
);
// Even if a listener fails, the circuit breaker continues working
$breaker->onSuccess(function ($event) {
throw new \Exception('Listener error!');
// This won't break the circuit breaker
});
$breaker->onSuccess(function (CallSucceededEvent $event) {
$executionTime = $event->getExecutionTime(); // in milliseconds
if ($executionTime > 500) {
$this->logger->warning('Slow response detected', [
'service' => $event->getServiceKey(),
'execution_time' => $executionTime,
]);
}
});
$breaker->onFailure(function (CallFailedEvent $event) {
// Track how long it took to fail
$this->metrics->timing('failure_time', $event->getExecutionTime());
});
$breaker->onSuccess(function (CallSucceededEvent $event) {
$result = $event->getResult(); // ✓ Reading is allowed
$time = $event->getExecutionTime(); // ✓ Reading is allowed
// Event properties are readonly - cannot be modified
});
use Farzai\Breaker\CircuitBreaker;
use Farzai\Breaker\Exceptions\CircuitOpenException;
use Farzai\Breaker\Storage\StorageFactory;
// Create with custom configuration and storage
$repository = StorageFactory::createRepository(
StorageFactory::file(__DIR__ . '/storage/circuit-breaker')
);
$breaker = new CircuitBreaker(
serviceKey: 'my-service',
config: [
'failure_threshold' => 5,
'timeout' => 30,
'success_threshold' => 2,
],
repository: $repository,
logger: $logger, // Optional PSR-3 logger
);
// Use the circuit breaker
try {
$result = $breaker->call(function () {
return callExternalService();
});
} catch (CircuitOpenException $e) {
return getBackupData();
}
// Or with fallback
$result = $breaker->callWithFallback(
fn() => callExternalService(),
fn($e, $breaker) => getBackupData()
);
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.