Fuse for Laravel: A Circuit Breaker Package for Queue Jobs
In the fast-paced world of web development, managing external service dependencies is crucial for maintaining the stability and performance of applications. One common issue developers face is the failure of queue workers when an external service goes down. This problem can lead to significant delays and resource wastage. To address this, Harris Raftopoulos introduced the Fuse package for Laravel, which implements the circuit breaker pattern to enhance the reliability of queue jobs.
The Problem
Imagine a scenario where your application relies on an external service, such as Stripe, for processing payments. It’s 11 PM, and Stripe experiences issues. Your queue workers, unaware of the problem, continue to attempt charging customers. Each job waits for a 30-second timeout before failing, and then it retries. If you have 10,000 payment jobs queued, the total time to clear the queue could exceed 25 hours, even though every request is destined to fail.
This situation not only leads to wasted resources but also affects the overall user experience. Fuse addresses this issue by implementing a circuit breaker pattern that intelligently manages these failures, ensuring that jobs fail quickly and are retried only when the external service is operational.
How the Circuit Breaker Works
The circuit breaker has three distinct states:
- CLOSED: This is the normal operation state where all requests are sent to the external service. Fuse tracks the success and failure rates of these requests using minute-based buckets that expire automatically.
- OPEN: In this state, the circuit has tripped due to a high failure rate exceeding a configured threshold. Jobs fail immediately without making an API call, and they are released back to the queue with a delay. This prevents the queue from getting clogged with failed jobs.
- HALF-OPEN: This state allows for a recovery test after a configurable timeout period. Fuse permits one probe request to pass through. If it succeeds, the circuit closes, resuming normal operations. If it fails, the circuit reopens, and the system waits again.
Installation
To install Fuse for Laravel, follow these simple steps:
- Run the following command to require the package:
- Publish the configuration file using the command:
composer require harris21/laravel-fuse
php artisan vendor:publish --tag=fuse-config
Basic Usage
Integrating Fuse into your Laravel jobs is straightforward. You need to add the middleware to any job that calls an external service. Here’s an example of how to implement it:
use Harris21FuseMiddlewareCircuitBreakerMiddleware;
class ChargeCustomer implements ShouldQueue {
public $tries = 0;
public $maxExceptions = 3;
public function middleware(): array {
return [new CircuitBreakerMiddleware('stripe')];
}
public function handle(): void {
Stripe::charges()->create([
'amount' => $this->amount,
'currency' => 'usd',
'customer' => $this->customerId,
]);
}
}
In this example, setting $tries = 0 allows unlimited releases since released jobs are not considered “retries” in Laravel’s context. The $maxExceptions = 3 property caps the actual failures, ensuring that the job itself does not require any changes as Fuse wraps around it seamlessly.
Configuration
The published configuration file allows you to set defaults and per-service overrides. Here’s a sample configuration:
// config/fuse.php
return [
'enabled' => env('FUSE_ENABLED', true),
'default_threshold' => 50,
'default_timeout' => 60,
'default_min_requests' => 10,
'services' => [
'stripe' => [
'threshold' => 50,
'timeout' => 30,
'min_requests' => 5,
],
'mailgun' => [
'threshold' => 60,
'timeout' => 120,
'min_requests' => 10,
],
],
];
The threshold represents the failure rate percentage. If 50% of requests fail within the tracking window, the circuit opens. The timeout indicates how many seconds to wait before testing for recovery, while min_requests prevents the circuit from tripping based on small sample sizes.
Intelligent Failure Classification
Not every error indicates that a service is down. For instance, if Stripe returns a 429 error due to rate limits, the service is functioning properly; it’s just overwhelmed. Fuse intelligently classifies failures, counting only those that signify actual service problems:
- 500, 502, 503 server errors count as failures.
- Connection timeouts and refused connections count as failures.
- 429 rate limits do not count as failures.
- 401 and 403 authentication errors do not count as failures.
This classification helps prevent false positives, ensuring that your circuit won’t trip simply because of an expired API key deployment.
Peak Hours Support
During business hours, you may want to be more tolerant of failures to maximize successful transactions. Conversely, outside business hours, you might prefer quicker protection. Fuse supports this flexibility:
'stripe' => [
'threshold' => 40,
'peak_hours_threshold' => 60,
'peak_hours_start' => 9,
'peak_hours_end' => 17,
],
In this configuration, between 9 AM and 5 PM, the circuit uses a 60% threshold, while outside those hours, it reverts to a 40% threshold. This allows you to balance protection and throughput based on transaction importance.
Events
Fuse dispatches Laravel events on every state transition. You can listen to these events for alerting purposes:
use Harris21FuseEventsCircuitBreakerOpened;
use Harris21FuseEventsCircuitBreakerHalfOpen;
use Harris21FuseEventsCircuitBreakerClosed;
class AlertOnCircuitOpen {
public function handle(CircuitBreakerOpened $event): void {
Log::critical("Circuit opened for {$event->service}", [
'failure_rate' => $event->failureRate,
'attempts' => $event->attempts,
'failures' => $event->failures,
]);
// Send to Slack, page on-call, etc.
}
}
The CircuitBreakerOpened event includes essential information such as the service name, current failure rate, total attempts, and failure count, which are useful for debugging and alerting.
Direct Usage
Fuse can also be utilized outside of queued jobs. Here’s an example of how to use the circuit breaker directly:
use Harris21FuseCircuitBreaker;
$breaker = new CircuitBreaker('stripe');
if (!$breaker->isOpen()) {
try {
$result = Stripe::charges()->create([...]);
$breaker->recordSuccess();
return $result;
} catch (Exception $e) {
$breaker->recordFailure($e);
throw $e;
}
} else {
return $this->fallbackResponse();
}
Additionally, you can check the state and reset the circuit manually:
$breaker->isClosed(); $breaker->isOpen(); $breaker->isHalfOpen(); $breaker->getStats(); $breaker->reset();
Thundering Herd Prevention
When a circuit enters the HALF-OPEN state, it is crucial to prevent multiple queue workers from sending probe requests simultaneously. Fuse addresses this by using Cache::lock() to ensure that only one worker tests the service while others continue to fail fast until the probe completes.
Requirements
To use Fuse for Laravel, ensure your environment meets the following requirements:
- PHP 8.3+
- Laravel 11+
- Any Laravel cache driver (Redis is recommended for production)
The package has no external dependencies and leverages Laravel’s native cache system for tracking and locks.
Conclusion
Fuse for Laravel brings the circuit breaker pattern to your applications with native integration and minimal configuration. By intelligently managing external service dependencies, it enhances the reliability of queue jobs, allowing developers to focus on building robust applications without the fear of external service failures derailing their operations.
Frequently Asked Questions
The Fuse package implements the circuit breaker pattern to manage external service dependencies, preventing queue workers from failing repeatedly when an external service is down.
The circuit breaker has three states: CLOSED (normal operation), OPEN (protection mode when failures exceed a threshold), and HALF-OPEN (testing recovery). It allows for efficient management of job failures and retries.
Yes, Fuse can be utilized directly in your code, allowing you to manage external service calls outside of the queued job context.
Call To Action
Enhance the reliability of your Laravel applications by integrating Fuse today. Don’t let external service failures disrupt your workflow. Start using Fuse for Laravel and experience seamless queue job management.
Note: Fuse for Laravel is designed to improve the stability of your applications by effectively managing external service dependencies, ensuring that your queue jobs operate efficiently even during service outages.

