laravel/horizon
Laravel Horizon adds a polished dashboard and code-driven configuration for Laravel Redis queues. Monitor job throughput, runtime, failures, and worker status, with all queue worker settings kept in a single config file for easy version control.
Installation:
composer require laravel/horizon
Publish Horizon's configuration and migrations:
php artisan horizon:install
Run migrations:
php artisan migrate
Configure Redis:
Ensure your config/horizon.php points to a Redis connection. Example:
'connections' => [
'redis' => [
'driver' => 'redis',
'connection' => 'redis',
'queue' => 'default',
'retry_after' => 90,
],
],
Start Horizon:
php artisan horizon
Access the dashboard at http://your-app.test/horizon.
Dispatch a job and monitor it:
// Dispatch a job
SendEmail::dispatch('user@example.com', 'Welcome!');
// Monitor via Horizon dashboard
// - View job status (processing, failed, etc.)
// - Check runtime, payload, and exceptions
Worker Configuration:
Define workers in config/horizon.php:
'workers' => [
'default' => [
'supervisor' => 'default',
'queue' => ['default'],
'balance' => 'auto',
'processes' => 1,
'tries' => 1,
],
],
balance: 'auto' for dynamic scaling.processes based on CPU cores (e.g., processes: 4).Job Tagging & Prioritization: Tag jobs for filtering in Horizon:
SendEmail::dispatch('user@example.com')->onQueue('emails')->tag(['newsletter', 'high-priority']);
Configure tags in config/horizon.php:
'tags' => [
'newsletter' => ['color' => 'blue', 'description' => 'Newsletter emails'],
],
Batch Processing: Group jobs into batches for unified monitoring:
$batch = Bus::batch([
new SendEmail('user1@example.com'),
new SendEmail('user2@example.com'),
])->then(function (Batch $batch) {
// Handle batch completion
})->dispatch();
View batches in Horizon under the "Batches" tab.
Supervisor Management:
Use php artisan horizon:terminate to gracefully shut down workers.
Restart supervisors via:
php artisan horizon:terminate && php artisan horizon
Event Listeners:
Listen to Horizon events (e.g., JobProcessed, JobFailed) for custom logic:
public function handle(JobProcessed $event) {
Log::info("Job {$event->job->id} processed in {$event->duration}ms");
}
Custom Metrics:
Extend Horizon’s monitoring with custom metrics via the Monitor facade:
use Illuminate\Support\Facades\Horizon;
Horizon::monitor('custom_metric', function () {
return Cache::get('custom_metric_value');
});
Environment-Specific Configs:
Use environment variables in config/horizon.php:
'processes' => env('QUEUE_WORKERS', 4),
Redis Connection Issues:
horizon (reserved).Memory Leaks:
horizon:listen (v5.43.0+) instead of horizon:work for long-running processes to prevent memory buildup.Job Stuck in "Pending":
Dashboard Not Loading:
php artisan horizon:clear-cache
Log Levels:
Increase Horizon’s log level in config/horizon.php:
'logging' => [
'driver' => 'single',
'level' => 'debug',
],
Job Payloads:
Inspect failed jobs’ payloads in the "Failed Jobs" tab. Use horizon:flush to clear old jobs:
php artisan horizon:flush --queue=failed
Worker Processes: Check process counts with:
php artisan horizon:status
Kill orphaned processes manually if needed.
Delayed Jobs:
Use delay() on jobs to schedule execution:
SendEmail::dispatch()->delay(now()->addMinutes(10));
Monitor delayed jobs in Horizon’s "Delayed" tab.
Silenced Tags: Hide specific tags from the dashboard:
'silenced_tags' => ['logs', 'internal'],
Custom Views:
Override Horizon’s Blade views in resources/views/vendor/horizon/.
Local Development:
Use horizon:listen --local to bypass private tunnel restrictions (v5.45.0+).
Batch Searching: Search across all jobs/batches using the global search bar (v5.45.0+).
PHP 8.5+ Compatibility:
Use horizon:listen for PHP 8.5+ to avoid setAccessible() deprecation warnings (v5.40.1+).
Worker Cooldown: Configure cooldowns for failed processes:
'cooldown' => [
'default' => 60, // seconds
],
How can I help you explore Laravel packages today?