4,000 emails/month for free | Mailtrap sends real emails now!

Laravel Fuse: A Circuit Breaker Package for Queue Jobs

Published on by

Laravel Fuse: A Circuit Breaker Package for Queue Jobs image

I just released Laravel Fuse on stage at Laracon India 2026. It's a package I built to solve a problem that's bitten me more than once: queue workers grinding to a halt when an external service goes down.

The Problem

Picture this scenario. It's 11 PM and Stripe is having issues. Your queue workers don't know that. They keep trying to charge customers, and each job waits 30 seconds for a timeout before failing. Then it retries. Waits again. Times out again.

If you have 10,000 payment jobs queued up and each one waits 30 seconds before timing out, you're looking at over 25 hours to clear the queue—even though every single request is going to fail.

Fuse fixes this by implementing the circuit breaker pattern. After a configurable number of failures, it stops making requests entirely. Jobs fail in milliseconds instead of waiting for timeouts, and they're automatically released back to the queue for later retry. When the service recovers, Fuse detects it and resumes normal operations.

How the Circuit Breaker Works

The circuit breaker has three states:

CLOSED is normal operation. All requests pass through to the external service. In the background, Fuse tracks success and failure rates using minute-based buckets that expire automatically.

OPEN is protection mode. Once the failure rate exceeds your configured threshold, the circuit trips. Jobs now fail immediately—no API call is made, no 30-second timeout. The job is released back to the queue with a delay. Your queue keeps moving.

HALF-OPEN is the recovery test. After a timeout period (configurable per service), Fuse allows one probe request through. If it succeeds, the circuit closes and normal operations resume. If it fails, the circuit reopens and waits again.

Installation

composer require harris21/laravel-fuse

Publish the configuration file:

php artisan vendor:publish --tag=fuse-config

Basic Usage

Add the middleware to any job that calls an external service:

use Harris21\Fuse\Middleware\CircuitBreakerMiddleware;
 
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,
]);
}
}

Setting $tries = 0 allows unlimited releases (since released jobs aren't "retries" in Laravel's sense), while $maxExceptions = 3 caps actual failures. The job itself doesn't need any changes—Fuse wraps around it.

Configuration

The published config file lets you set defaults and per-service overrides:

// 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 is a failure rate percentage. If 50% of requests fail within the tracking window, the circuit opens. The timeout is how many seconds to wait before testing recovery. And min_requests prevents the circuit from tripping on small sample sizes—you need at least this many requests before the failure rate is evaluated.

Intelligent Failure Classification

Not every error means a service is down. If Stripe returns a 429 because you're hitting rate limits, that's not an outage—the service is working fine, you're just sending too many requests. Same with authentication errors.

Fuse only counts failures that indicate 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
  • 401 and 403 auth errors do not count

This prevents false positives. Your circuit won't trip just because someone deployed with an expired API key.

Peak Hours Support

During business hours, you might want to be more tolerant of failures to maximize successful transactions. Outside business hours, you might prefer earlier protection. Fuse supports this:

'stripe' => [
'threshold' => 40,
'peak_hours_threshold' => 60,
'peak_hours_start' => 9,
'peak_hours_end' => 17,
],

Between 9 AM and 5 PM, the circuit uses the 60% threshold. Outside those hours, it uses 40%. This lets you tune the tradeoff between protection and throughput based on when transactions matter most.

Events

Fuse dispatches Laravel events on every state transition:

use Harris21\Fuse\Events\CircuitBreakerOpened;
use Harris21\Fuse\Events\CircuitBreakerHalfOpen;
use Harris21\Fuse\Events\CircuitBreakerClosed;

You can listen to these for alerting:

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 the service name, current failure rate, total attempts, and failure count. This gives you what you need for debugging and alerting.

Direct Usage

You can also use the circuit breaker outside of queued jobs:

use Harris21\Fuse\CircuitBreaker;
 
$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();
}

You can also check state and reset manually:

$breaker->isClosed();
$breaker->isOpen();
$breaker->isHalfOpen();
$breaker->getStats();
$breaker->reset();

Thundering Herd Prevention

When a circuit enters HALF-OPEN, you don't want 50 queue workers all sending probe requests simultaneously. Fuse uses Cache::lock() to ensure only one worker tests the service. The others continue failing fast until the probe completes.

Requirements

  • PHP 8.3+
  • Laravel 11+
  • Any Laravel cache driver (Redis recommended for production)

The package has no external dependencies. It uses Laravel's native cache system for tracking and locks.

Links

The circuit breaker pattern comes from Michael Nygard's Release It! and was later popularized by Martin Fowler. Fuse brings it to Laravel with native integration and zero configuration for basic use cases.

Harris Raftopoulos photo

Senior Software Engineer • Staff & Educator @ Laravel News • Co-organizer @ Laravel Greece Meetup

Filed in:
Cube

Laravel Newsletter

Join 40k+ other developers and never miss out on new tips, tutorials, and more.

image
Bacancy

Outsource a dedicated Laravel developer for $3,200/month. With over a decade of experience in Laravel development, we deliver fast, high-quality, and cost-effective solutions at affordable rates.

Visit Bacancy
Curotec logo

Curotec

World class Laravel experts with GenAI dev skills. LATAM-based, embedded engineers that ship fast, communicate clearly, and elevate your product. No bloat, no BS.

Curotec
Bacancy logo

Bacancy

Supercharge your project with a seasoned Laravel developer with 4-6 years of experience for just $3200/month. Get 160 hours of dedicated expertise & a risk-free 15-day trial. Schedule a call now!

Bacancy
Tinkerwell logo

Tinkerwell

The must-have code runner for Laravel developers. Tinker with AI, autocompletion and instant feedback on local and production environments.

Tinkerwell
Get expert guidance in a few days with a Laravel code review logo

Get expert guidance in a few days with a Laravel code review

Expert code review! Get clear, practical feedback from two Laravel devs with 10+ years of experience helping teams build better apps.

Get expert guidance in a few days with a Laravel code review
PhpStorm logo

PhpStorm

The go-to PHP IDE with extensive out-of-the-box support for Laravel and its ecosystem.

PhpStorm
Laravel Cloud logo

Laravel Cloud

Easily create and manage your servers and deploy your Laravel applications in seconds.

Laravel Cloud
Kirschbaum logo

Kirschbaum

Providing innovation and stability to ensure your web application succeeds.

Kirschbaum
Shift logo

Shift

Running an old Laravel version? Instant, automated Laravel upgrades and code modernization to keep your applications fresh.

Shift
Harpoon: Next generation time tracking and invoicing logo

Harpoon: Next generation time tracking and invoicing

The next generation time-tracking and billing software that helps your agency plan and forecast a profitable future.

Harpoon: Next generation time tracking and invoicing
Lucky Media logo

Lucky Media

Get Lucky Now - the ideal choice for Laravel Development, with over a decade of experience!

Lucky Media
SaaSykit: Laravel SaaS Starter Kit logo

SaaSykit: Laravel SaaS Starter Kit

SaaSykit is a Multi-tenant Laravel SaaS Starter Kit that comes with all features required to run a modern SaaS. Payments, Beautiful Checkout, Admin Panel, User dashboard, Auth, Ready Components, Stats, Blog, Docs and more.

SaaSykit: Laravel SaaS Starter Kit

The latest

View all →
Laravel Fuse: A Circuit Breaker Package for Queue Jobs image

Laravel Fuse: A Circuit Breaker Package for Queue Jobs

Read article
Generate Complete Application Modules with a Single Command using Laravel TurboMaker image

Generate Complete Application Modules with a Single Command using Laravel TurboMaker

Read article
`hasSole()` Collection Method in Laravel 12.49.0 image

`hasSole()` Collection Method in Laravel 12.49.0

Read article
Install Laravel Package Guidelines and Skills in Boost image

Install Laravel Package Guidelines and Skills in Boost

Read article
Bagisto Visual: Theme Framework with Visual Editor for Laravel E-commerce image

Bagisto Visual: Theme Framework with Visual Editor for Laravel E-commerce

Read article
Clawdbot Rebrands to Moltbot After Trademark Request From Anthropic image

Clawdbot Rebrands to Moltbot After Trademark Request From Anthropic

Read article