4 minutes read
The Laravel failover queue driver: stop losing jobs
Table of contents
- → What is the Laravel failover queue driver?
- → Quick start (copy-paste)
- → How to run workers and Horizon (don’t point them at failover)
- → Three practical patterns (pick one)
- → How you can test the failover driver
- → Get a heads-up when failover happens (simple event listener)
- → Gotchas I noted while testing
- → FAQ
- → Final thought
What is the Laravel failover queue driver?
It’s a queue driver named failover and available starting in Laravel 12.34. First, list your queue connections in order in config/queues.php. Then, when you push a job, Laravel tries the first one. If it fails, it automatically tries the next one and so on.
Benefits:
- It’s effortless.
- You only have your config to change.
- You have less chances of losing jobs to dead connections.
Quick start (copy-paste)
1. Set your default queue to failover
In .env:
QUEUE_CONNECTION=failover
2. Add a failover connection
In config/queue.php:
'connections' => [ // Normal connections… 'database' => [ 'driver' => 'database', 'table' => 'jobs', 'queue' => 'default', 'retry_after' => 90, 'after_commit' => false, ], 'redis' => [ 'driver' => 'redis', 'connection' => 'default', 'queue' => 'default', 'retry_after' => 90, 'block_for' => null, 'after_commit' => false, ], // NEW: the Laravel failover queue driver. 'failover' => [ 'driver' => 'failover', 'connections' => [ // Try Redis first. If it fails, fall back to database. 'redis', 'database', ], ], ],
Now dispatch jobs like you always do:
SendWelcomeEmail::dispatch($user->id);
If Redis is down, the job is pushed to the database queue instead.
How to run workers and Horizon (don’t point them at failover)
The failover driver falls back when pushing jobs. When consuming jobs, the failover connection only reads from the first listed connection (for example, redis). So if a push fell back to database, a worker pointed at failover won’t see those jobs.
Run workers for each connection you might use:
# Keep your fast path. php artisan queue:work redis --queue=default # Also run a worker for the fallback path. php artisan queue:work database --queue=default
Horizon example (config/horizon.php)
'supervisors' => [ 'redis' => [ 'connection' => 'redis', 'queue' => ['default'], 'balance' => 'simple', 'maxProcesses' => 5, ], 'database' => [ 'connection' => 'database', 'queue' => ['default'], 'balance' => 'simple', 'maxProcesses' => 2, ], ],
This way, if pushes fall back to database, you still have a worker ready to process those jobs.
Three practical patterns (pick one)
A. Speed first, safety second (Redis → database)
Good for most apps.
'connections' => [ 'failover' => [ 'driver' => 'failover', 'connections' => ['redis', 'database'], ], ],
B. Small tools and admin panels (Redis → sync)
If anything breaks, just run the job now so users aren’t blocked.
'connections' => [ 'failover' => [ 'driver' => 'failover', 'connections' => ['redis', 'sync'], ], ],
C. Bigger apps (Redis → SQS → database)
Keep performance and add cloud durability.
'connections' => [ 'failover' => [ 'driver' => 'failover', 'connections' => ['redis', 'sqs', 'database'], ], ],
How you can test the failover driver
- Start your worker(s) (Horizon or
php artisan queue:workfor each connection). - Stop Redis to simulate a failure:
- Docker:
docker stop redis - Homebrew:
brew services stop redis
- Docker:
- Dispatch a job.
- Check your logs and, if you use database fallback, check the
jobstable:
SELECT id, queue, attempts, available_at FROM jobs ORDER BY id DESC LIMIT 10;
- Start Redis again when you’re done.
You’ll see jobs pushed to the next connection when Redis is down.
Get a heads-up when failover happens (simple event listener)
Laravel fires a QueueFailedOver event when it switches connections. You can log it (or ping Slack).
App\Providers\EventServiceProvider.php
protected $listen = [ \Illuminate\Queue\Events\QueueFailedOver::class => [ \App\Listeners\NotifyOnQueueFailover::class, ], ];
App\Listeners\NotifyOnQueueFailover.php
namespace App\Listeners; use Illuminate\Support\Facades\Log; use Illuminate\Queue\Events\QueueFailedOver; class NotifyOnQueueFailover { public function handle(QueueFailedOver $event): void { Log::critical('Queue failover occurred', [ 'failed_connection' => $event->connectionName, 'job' => is_object($event->command) ? get_class($event->command) : $event->command, ]); // Or send to Slack / email from here. } }
Now you’ll know right away when the Laravel failover queue driver had to save you.
Gotchas I noted while testing
- Failover is for pushing. It doesn’t merge or drain multiple connections later. Workers won’t “fall through” to read another connection.
- If all listed connections fail at push-time, Laravel throws an exception and the job is not queued.
pushRaw()won’t fire theQueueFailedOverevent; onlypush()andlater()do.- Make jobs idempotent (safe to run twice with the same result) in case a flaky connection causes retries.
- If you fall back to
databaseorsqs, make sure your jobs serialize cleanly.
FAQ
Does this work with Horizon?
Yes. But don’t point Horizon at failover. Run a supervisor for each connection you list (for example, one for redis, one for database).
Can I use any connection type?
Yes. redis, sqs, database, beanstalkd, or even sync.
Final thought
I like features that are “set it and forget it.” The Laravel failover queue driver is exactly that. You set QUEUE_CONNECTION=failover, list your backups in config/queue.php, and your app keeps moving when one service goes down. That’s less stress for you, and a smoother experience for your users.
Did you like this article? Then, keep learning:
- Fix common Laravel queue error related to database transactions
- Stop Laravel CSRF token issues causing 419 Page Expired error
- Understand how to handle middleware customization in Laravel 11+
- Master error handling in Laravel's HTTP client for smooth operations
- Learn about Laravel 10 upgrade including new features and queue improvements
- Discover Laravel 11 new features that improve reliability and app performance
- See Laravel 12 changes including starter kits enhancing your app setup
- Explore 25 Laravel best practices including efficient queue management
- Monitor your Laravel apps and queues with Laravel Pulse monitoring tool
- Learn 9 testing best practices to improve Laravel app reliability
0 comments