Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Horizon Laravel Package

laravel/horizon

Laravel Horizon adds a polished dashboard and code-driven configuration for Laravel Redis queues. Monitor throughput, runtimes, and failed jobs, and manage all worker and supervisor settings from a single config file kept in source control.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require laravel/horizon
    

    Publish Horizon's configuration file:

    php artisan horizon:publish
    
  2. Configure Redis: Ensure your config/horizon.php points to a Redis connection (default: redis).

    'connections' => [
        'redis' => [
            'driver' => 'redis',
            'connection' => 'redis',
            'queue' => 'default',
            'retry_after' => 90,
        ],
    ],
    
  3. Run Horizon: Start the dashboard and workers:

    php artisan horizon
    

    Access the dashboard at http://your-app.test/horizon.

  4. First Use Case: Dispatch a job and monitor it in real-time:

    dispatch(new ProcessPodcast);
    

    Check the dashboard for job status, runtime, and failures.


Implementation Patterns

Daily Workflows

  1. Job Monitoring:

    • Use the dashboard to track job throughput, failures, and runtime.
    • Filter jobs by tags, batches, or connection using the UI.
  2. Worker Configuration:

    • Define worker processes in config/horizon.php:
      'processes' => [
          'default' => [
              'balance' => ['SendPodcastEmail', 'ProcessPodcast'],
              'supervisor' => 'throttle:10',
              'tries' => 3,
          ],
      ],
      
    • Leverage balance to distribute jobs across workers and supervisor to throttle or batch jobs.
  3. Batch Processing:

    • Group jobs into batches for atomic operations:
      $batch = Batch::dispatch(function () {
          ProcessPodcast::dispatch($podcast1);
          ProcessPodcast::dispatch($podcast2);
      });
      
    • Monitor batch progress and failures in the dashboard.
  4. Delayed and Retry Jobs:

    • Dispatch delayed jobs:
      ProcessPodcast::dispatch($podcast)->delay(now()->addMinutes(10));
      
    • Use the dashboard to retry failed jobs or adjust retry logic in config/horizon.php:
      'retry_via' => 'database',
      'retry_after' => 90,
      
  5. Custom Job Events:

    • Extend job behavior with events (e.g., JobProcessed, JobFailed):
      ProcessPodcast::dispatch($podcast)->onQueue('podcasts')->onConnection('redis');
      
    • Listen for events in EventServiceProvider:
      protected $listen = [
          'JobFailed' => [
              'App\Listeners\LogFailedJob',
          ],
      ];
      
  6. Environment-Specific Config:

    • Override Horizon config per environment (e.g., config/horizon-local.php):
      'processes' => [
          'local' => [
              'balance' => ['*'],
              'supervisor' => 'simple-queue',
          ],
      ],
      
    • Load it in config/horizon.php:
      $config = require __DIR__.'/horizon.php';
      if (app()->environment('local')) {
          $config = array_merge($config, require __DIR__.'/horizon-local.php');
      }
      return $config;
      
  7. CLI Integration:

    • Use horizon:listen for local development:
      php artisan horizon:listen --queue=podcasts
      
    • Reload workers dynamically:
      php artisan horizon:reload
      
  8. Testing:

    • Mock Horizon in tests using Horizon::fake():
      public function test_job_processing()
      {
          Horizon::fake();
          ProcessPodcast::dispatch($podcast);
          $this->assertProcessed(ProcessPodcast::class);
      }
      

Gotchas and Tips

Pitfalls

  1. Redis Connection Issues:

    • Ensure Redis is running and accessible. Horizon fails fast if Redis is unavailable (v5.45.0+).
    • Avoid using the reserved horizon connection name (v5.35.0+).
  2. Memory Leaks:

    • Monitor worker memory usage in the dashboard. Use horizon:terminate to restart workers if needed.
    • Fix runaway memory usage with horizon:listen (v5.45.1).
  3. Job Stuck in Pending:

    • Race conditions can leave jobs pending. Use horizon:flush to clear stale jobs or fix the race condition (v5.42.0).
  4. Large Queue Backlogs:

    • Pagination issues may arise with thousands of jobs. Use batch searching (v5.45.0) or optimize Redis keys.
  5. Environment-Specific Quirks:

    • Local tunnels may expose Horizon unintentionally. Restrict private tunnel requests for local environments (v5.45.0).
  6. Deprecated Features:

    • horizon:publish is deprecated (v5.45.0). Use horizon:install instead.

Debugging Tips

  1. Logs:

    • Check storage/logs/horizon.log for worker errors.
    • Enable debug mode in config/horizon.php:
      'debug' => env('APP_DEBUG', false),
      
  2. Job Inspection:

    • Use horizon:inspect to debug specific jobs:
      php artisan horizon:inspect <job-id>
      
  3. Worker Supervision:

    • Monitor supervisor health in the dashboard. Use horizon:terminate to restart workers gracefully.
  4. Redis Cluster Support:

    • Horizon supports Redis Cluster (v5.46.0). Ensure your config/redis.php is configured for clustering:
      'cluster' => [
          'driver' => 'predis',
          'connection' => 'redis',
          'options' => [
              'cluster' => 'redis',
          ],
      ],
      
  5. Performance Tuning:

    • Adjust balance and supervisor settings to optimize throughput.
    • Use throttle to limit job processing rates:
      'supervisor' => 'throttle:10',
      
  6. Customizing the Dashboard:

    • Extend Horizon's Blade views (e.g., resources/views/vendor/horizon/layouts/app.blade.php).
    • Override CSS/JS in public/vendor/horizon.
  7. Silencing Tags:

    • Hide specific tags from the dashboard using silenced_tags (v5.34.0):
      'silenced_tags' => ['logs', 'notifications'],
      
  8. PHP 8.5+ Compatibility:

    • Use setAccessible() guard for PHP 8.5+ (v5.40.1). Example:
      if (method_exists($model, 'setAccessible')) {
          $model->setAccessible(['attribute']);
      } else {
          $model->setFillable(['attribute']);
      }
      

Extension Points

  1. Custom Job Metrics:

    • Extend Horizon\Jobs\Job to add custom metrics:
      class ProcessPodcast extends Job
      {
          public function handle()
          {
              // Custom logic
              $this->recordMetrics(['podcast_id' => $this->podcast->id]);
          }
      }
      
  2. Event Listeners:

    • Listen to Horizon events (e.g., JobProcessed, SupervisorTerminated):
      public function boot()
      {
          Horizon::routeJobFailed(function ($exception, $job) {
              Log::error("Job failed: {$job->getJobId()}", [
                  'exception' => $exception,
                  'job' => $job,
              ]);
          });
      }
      
  3. Middleware:

    • Add middleware to jobs for cross-cutting concerns:
      class LogJobMiddleware
      {
          public function handle($job, Closure $next)
          {
              Log::info("Processing job {$job->getJobId()}");
              return $next($job);
          }
      }
      
      Register in AppServiceProvider:
      Horizon::middleware([LogJobMiddleware::class]);
      
  4. Custom Supervisors:

    • Implement Horizon\Supervisors\Supervisor for custom worker logic:
      class CustomSupervisor extends Supervisor
      {
          public function start()
          {
              // Custom startup logic
          }
      
          public function stop()
          {
              // Custom shutdown logic
          }
      }
      
      Register in config/horizon.php:
      'supervisors' => [
          'custom' => CustomSupervisor::class,
      ],
      
  5. Batch Customization:

    • Extend Horizon\Jobs\Batch for custom batch behavior:
      class CustomBatch extends Batch
      {
          public function handle()
          {
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai