Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Php Circuit Breaker Bundle Laravel Package

ejsmont-artur/php-circuit-breaker-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install via Composer:
    composer require ejsmont-artur/php-circuit-breaker-bundle
    
  2. Enable the Bundle in config/bundles.php:
    return [
        // ...
        Ejsmont\CircuitBreakerBundle\EjsmontCircuitBreakerBundle::class => ['all' => true],
    ];
    
  3. Configure Cache (optional, but recommended for persistence):
    # config/packages/ejsmont_circuit_breaker.yaml
    ejsmont_circuit_breaker:
        cache: cache.app  # Default Symfony cache service
    

First Use Case: Protecting an External API Call

use Ejsmont\CircuitBreaker\CircuitBreaker;
use Ejsmont\CircuitBreaker\CircuitBreakerException;

class PaymentService
{
    private $circuitBreaker;
    private $paymentGateway;

    public function __construct(
        CircuitBreaker $circuitBreaker,
        PaymentGateway $paymentGateway
    ) {
        $this->circuitBreaker = $circuitBreaker;
        $this->paymentGateway = $paymentGateway;
    }

    public function processPayment(float $amount)
    {
        $this->circuitBreaker->execute(
            'payment_gateway', // Unique identifier for the circuit
            function () use ($amount) {
                return $this->paymentGateway->charge($amount);
            },
            3, // Max retries
            1000 // Timeout in ms
        );
    }
}

Implementation Patterns

1. Service Integration

  • Dependency Injection: Inject CircuitBreaker service directly into controllers/services.
  • Named Circuits: Use descriptive names (e.g., external_api, database_replica) for clarity.
  • Configuration via YAML:
    ejsmont_circuit_breaker:
        circuits:
            payment_gateway:
                max_retries: 3
                timeout: 1000
                fallback: App\Service\PaymentFallbackService
    

2. Fallback Strategies

  • Default Fallback: Return cached data or a static response.
    $result = $this->circuitBreaker->execute(
        'api_call',
        fn() => $externalApi->fetchData(),
        2,
        500,
        fn() => $this->fallbackService->getCachedData()
    );
    
  • Custom Fallback Logic: Implement Ejsmont\CircuitBreaker\FallbackInterface.

3. Event Listeners

  • Monitor State: Listen to circuit_breaker.state_changed events.
    // src/EventListener/CircuitBreakerListener.php
    public function onStateChanged(CircuitBreakerEvent $event)
    {
        if ($event->isOpen()) {
            $this->logger->warning('Circuit opened for: '.$event->getName());
        }
    }
    
    Register in services.yaml:
    services:
        App\EventListener\CircuitBreakerListener:
            tags:
                - { name: kernel.event_listener, event: circuit_breaker.state_changed }
    

4. Dynamic Circuit Configuration

  • Runtime Overrides: Use CircuitBreakerFactory to create circuits dynamically.
    $factory = $container->get('ejsmont_circuit_breaker.factory');
    $circuit = $factory->create('dynamic_circuit', [
        'max_retries' => $this->getMaxRetriesFromConfig(),
    ]);
    

5. Testing

  • Mock Circuits: Use CircuitBreakerMock for unit tests.
    $mock = new CircuitBreakerMock('test_circuit');
    $mock->setState(CircuitBreaker::STATE_OPEN);
    $this->service->setCircuitBreaker($mock);
    

Gotchas and Tips

Pitfalls

  1. Cache Dependency:

    • Without a cache backend, state is lost on restart. Configure cache in ejsmont_circuit_breaker.yaml.
    • Fix: Use cache.app or a dedicated cache pool (e.g., cache.doctrine).
  2. Timeout Handling:

    • Timeouts are per attempt, not total. Adjust timeout for slow dependencies.
    • Tip: Use 0 for no timeout (not recommended for external calls).
  3. State Persistence:

    • Circuits reset to CLOSED after reset_timeout (default: 60s). Override in config:
      ejsmont_circuit_breaker:
          reset_timeout: 300 # 5 minutes
      
  4. Fallback Misuse:

    • Fallbacks should be idempotent and lightweight. Avoid calling other circuits in fallbacks (risk of cascading failures).
  5. Symfony 3+ Compatibility:

    • The bundle targets Symfony 2. For Symfony 3/4/5, ensure service.xml is loaded via config/packages/ejsmont_circuit_breaker.xml.

Debugging Tips

  • Log State Changes:
    ejsmont_circuit_breaker:
        logger: true # Enables logging via Symfony's logger
    
  • Inspect State:
    $state = $this->circuitBreaker->getState('circuit_name');
    // $state->isOpen(), $state->getFailureCount(), etc.
    
  • Reset Circuits Manually:
    $this->circuitBreaker->reset('circuit_name');
    

Extension Points

  1. Custom States:

    • Extend Ejsmont\CircuitBreaker\State to add custom logic (e.g., HALF_OPEN with custom retry rules).
  2. Metrics Integration:

    • Integrate with Symfony Monitor or Prometheus by tapping into circuit_breaker.state_changed.
  3. Async Support:

    • Combine with Symfony Messenger for async circuit-breaking:
      $message = new PaymentMessage($amount);
      $this->bus->dispatch($message);
      // Circuit breaker wraps the message handler.
      
  4. Rate Limiting:

    • Use max_retries to indirectly limit request rates (e.g., max_retries: 1 for strict rate limiting).

Performance Considerations

  • Avoid Overhead: Use circuits only for external or unreliable dependencies (e.g., APIs, replicas).
  • Cache Warmup: Pre-warm fallbacks to avoid cold-start latency.
  • Concurrency: Circuits are not thread-safe by default. Use a single instance per request in Symfony.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
nasirkhan/laravel-sharekit
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony