Managing Background Job Visibility with Laravel Horizon
Stop guessing why your background jobs are failing. Learn how to use Laravel Horizon to monitor Redis queues, debug failed jobs, and manage worker scaling.
08 Apr 2026, 16:47 UTC

The Problem: The "Black Box" of Background Queues
When your Laravel application offloads tasks—like sending welcome emails or processing CSV uploads—to a queue, those tasks enter a "black box." If a job fails or a queue backs up, you often don't know until a user reports a bug or your database fills with pending records. Checking raw logs or running redis-cli commands is slow and doesn't provide a high-level view of system health.
The Takeaway
Laravel Horizon provides a real-time dashboard and configuration system for Redis-powered queues. It allows you to monitor job throughput, inspect failed jobs with full stack traces, and manage worker counts through a single configuration file, turning opaque background processes into observable data.
Setting Up Horizon
Horizon requires Redis to function; it is not compatible with the database or sqs queue drivers. Ensure your .env file is set to QUEUE_CONNECTION=redis.
- Install the package (run in project root):
composer require laravel/horizon php artisan horizon:install - Start the process (run in terminal with permissions to execute Artisan):
php artisan horizonNote: In production, this process should be managed by a process monitor like Supervisor to ensure it restarts after server reboots or crashes.
- Access the UI: Navigate to
/horizonon your application URL. By default, access is restricted to the local environment.
Worked Example: Monitoring a Failing Job
To see Horizon's value, create a job designed to fail and observe how the dashboard handles it.
1. Create the job:
php artisan make:job FailureTestJob
2. Force an exception in app/Jobs/FailureTestJob.php:
public function handle()
{
throw new \Exception('Simulated job failure for Horizon testing');
}
3. Dispatch via Tinker:
php artisan tinker
> App\\Jobs\\FailureTestJob::dispatch();
4. Verify in Horizon:
- Navigate to the Failed Jobs tab.
- You will see the
FailureTestJoblisted with the exact exception message and a timestamp. - You can click the "Retry" button directly in the UI to push the job back into the queue without manual CLI intervention.
Engineering Trade-offs and Limitations
Resource Consumption
Horizon is a long-lived PHP process that manages several child worker processes. Each worker consumes a slice of system memory (typically 50MB–100MB depending on your app's footprint). On small VPS instances with limited RAM, running too many workers via Horizon can lead to Out-of-Memory (OOM) errors.
The Scaling Caveat
While Horizon supports "Auto-scaling" (adjusting worker counts based on queue length), this is natively integrated with Laravel Vapor. On traditional bare-metal or VM setups, you must manually define the maxProcesses and minProcesses in config/horizon.php to prevent the server from being overwhelmed during traffic spikes.
Production Security
Because the dashboard reveals sensitive job data and allows job retries, you must secure the route. In app/Providers/HorizonServiceProvider.php, define the gate to restrict access:
Gate::define('viewHorizon', function ($user) {
return in_array($user->email, ['[contact removed]']);
});
Verification and Rollback
To verify the installation is active, check the Metrics page in the dashboard; you should see a real-time graph of "Jobs per minute." If the page is blank, run redis-cli ping to ensure the Redis server is responding with PONG.
Rollback: To remove Horizon, remove the package via composer and delete the configuration file:
composer remove laravel/horizon
rm config/horizon.php0 replies
A thoughtful contribution can make all the difference. Be the first to share one.