pexels tima miroshnichenko 5380589

Laravel Horizon: Queue Monitoring, Scaling, and Management

·

Once your Laravel application starts doing meaningful work in the background – sending emails, processing uploads, syncing with third-party APIs, generating reports – you need visibility into what’s happening in your queues. Queue workers running silently in the background are fine until they’re not: jobs failing silently, queues backing up, workers dying without restarting. Laravel Horizon gives you a real-time dashboard for all of it, with the configuration tooling to control how your workers scale.

Requirements and Installation

Horizon requires Redis as the queue driver – it won’t work with the database or SQS drivers.

composer require laravel/horizon
php artisan horizon:install
php artisan migrate
php artisan horizon

Understanding the Configuration

// config/horizon.php
'environments' => [
    'production' => [
        'supervisor-1' => [
            'connection' => 'redis',
            'queue' => ['high', 'default', 'low'],
            'balance' => 'auto',
            'autoScalingStrategy' => 'time',
            'maxProcesses' => 10,
            'memory' => 128,
            'tries' => 3,
            'timeout' => 60,
        ],
    ],
    'local' => [
        'supervisor-1' => [
            'connection' => 'redis',
            'queue' => ['high', 'default', 'low'],
            'balance' => 'simple',
            'minProcesses' => 1,
            'maxProcesses' => 3,
            'tries' => 1,
        ],
    ],
],

Queue Priority

// Workers check queues in order - high first, then default, then low
dispatch(new SendWelcomeEmail($user))->onQueue('high');
dispatch(new ProcessReport($report))->onQueue('default');
dispatch(new SendMarketingEmail($user))->onQueue('low');

// Or define queue on the job class
class ProcessReport implements ShouldQueue
{
    public string $queue = 'default';
}

Balance Strategies

  • Simple – distributes workers equally across queues. Good for development.
  • Auto – shifts workers dynamically based on queue depth. Use this in production.
  • False – fixed process count. Use when you need predictable resource consumption.
'balance' => 'auto',
'minProcesses' => 1,
'maxProcesses' => 10,
'balanceCooldown' => 3,  // Seconds between scaling decisions

The Dashboard

Access at /horizon. Key metrics: Throughput (jobs per minute), Runtime (average job execution time), Wait Time (time jobs sit in queue before pickup – the key latency metric), Failed Jobs (with exception and retry button), Pending Jobs (per queue).

Securing the Dashboard

// app/Providers/HorizonServiceProvider.php
protected function gate(): void
{
    Gate::define('viewHorizon', function ($user) {
        return in_array($user->email, [
            'developer@yourcompany.com',
        ]);
    });
}

Deploying with Supervisor

# /etc/supervisor/conf.d/horizon.conf
[program:horizon]
process_name=%(program_name)s
command=php /var/www/your-app/artisan horizon
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/log/horizon.log
stopwaitsecs=3600  # Wait up to 1 hour for jobs to finish

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start horizon

Deployment Workflow

# Terminate gracefully (waits for current jobs to finish)
php artisan horizon:terminate

# Restart immediately
php artisan horizon:restart

# Check status
php artisan horizon:status

Failed Jobs

php artisan queue:failed
php artisan queue:retry [id]
php artisan queue:retry all
php artisan queue:flush

Metrics and Health Monitoring

# Schedule snapshots for historical data
Schedule::command('horizon:snapshot')->everyFiveMinutes();

# Health check endpoint (use in uptime monitoring)
curl http://your-app.com/horizon/api/health-check
# Returns 200 if running, 503 if not

Conclusion

Horizon is one of those tools that pays for its installation cost on the first deployment incident it helps you diagnose. The wait time metric alone – seeing jobs pile up because workers are overwhelmed – gives you the data to scale before users notice. Set it up in production with Supervisor and add the health check endpoint to your uptime monitoring.


Leave a Reply