Vai al contenuto principale

Cos’è Horizon

Laravel Horizon è la dashboard di monitoraggio dedicata alle code Redis di Laravel. Visualizza in tempo reale throughput, tempi di esecuzione e fallimenti dei job e gestisci la configurazione dei worker via codice.
Horizon estende le funzionalità di base delle code. Consulta prima Code e job e assicurati che sia disponibile Redis.

Installazione

Horizon usa Redis. Verifica che QUEUE_CONNECTION in config/queue.php sia redis. Al momento non supporta Redis Cluster.
Installazione:
composer require laravel/horizon
Pubblica asset e configurazione:
php artisan horizon:install
Vengono generati config/horizon.php e app/Providers/HorizonServiceProvider.php.

Configurazione

Struttura di config/horizon.php

config/horizon.php gestisce le impostazioni dei worker. Il centro è environments.
'environments' => [
    'production' => [
        'supervisor-1' => [
            'connection' => 'redis',
            'queue' => ['default', 'notifications'],
            'balance' => 'auto',
            'autoScalingStrategy' => 'time',
            'minProcesses' => 1,
            'maxProcesses' => 10,
            'balanceMaxShift' => 1,
            'balanceCooldown' => 3,
            'tries' => 3,
            'timeout' => 60,
        ],
    ],

    'local' => [
        'supervisor-1' => [
            'maxProcesses' => 3,
        ],
    ],
],
Horizon usa internamente una connessione Redis chiamata horizon. Non riutilizzare questo nome in config/database.php.

Supervisor

Ogni environment ha uno o più “supervisor”. Sono unità di gestione dei worker: puoi avere più supervisor con diverse code, strategie e numero di processi.

Default

Con defaults imposti valori comuni a tutti i supervisor.
'defaults' => [
    'supervisor-1' => [
        'connection' => 'redis',
        'queue' => ['default'],
        'balance' => 'auto',
        'tries' => 1,
        'timeout' => 60,
        'maxProcesses' => 1,
    ],
],

Modalità manutenzione

Di default Horizon non elabora job in manutenzione. Con force sì.
'environments' => [
    'production' => [
        'supervisor-1' => [
            'force' => true,
        ],
    ],
],

Tentativi

'environments' => [
    'production' => [
        'supervisor-1' => [
            'tries' => 10,
        ],
    ],
],
0 = tentativi illimitati.

Timeout

'environments' => [
    'production' => [
        'supervisor-1' => [
            'timeout' => 60,
        ],
    ],
],
timeout deve essere qualche secondo minore di retry_after in config/queue.php. La strategia auto può terminare job più lunghi.

Backoff

// Fisso
'backoff' => 10,

// Esponenziale
'backoff' => [1, 5, 10],

Strategie di bilanciamento

Regola il numero di worker in base al carico.
'supervisor-1' => [
    'balance' => 'auto',
    'autoScalingStrategy' => 'time', // o 'size'
    'minProcesses' => 1,
    'maxProcesses' => 10,
    'balanceMaxShift' => 1,
    'balanceCooldown' => 3,
],
  • time — tempo stimato per svuotare la coda
  • size — numero di job in coda
Con auto l’ordine delle code non implica priorità. Per priorità stretta usa più supervisor.
Numero di worker fisso, distribuiti tra le code.
'supervisor-1' => [
    'balance' => 'simple',
    'processes' => 10,
    'queue' => ['default', 'notifications'],
],
5 processi per coda.
Priorità stretta secondo l’ordine delle code.
'supervisor-1' => [
    'balance' => false,
    'queue' => ['default', 'notifications'],
    'minProcesses' => 1,
    'maxProcesses' => 10,
],
default sempre prima di notifications.

Autorizzazione della dashboard

La dashboard è su /horizon. In locale è accessibile a tutti; in produzione limita con una gate. Modifica gate() in app/Providers/HorizonServiceProvider.php.
use App\Models\User;
use Illuminate\Support\Facades\Gate;

protected function gate(): void
{
    Gate::define('viewHorizon', function (User $user) {
        return in_array($user->email, [
            '[email protected]',
        ]);
    });
}
Senza autenticazione (protetto da IP, ad esempio):
Gate::define('viewHorizon', function (User $user = null) {
    return true;
});

Avvio di Horizon

Comandi base

# Avvio
php artisan horizon

# Pausa / ripresa
php artisan horizon:pause
php artisan horizon:continue

# Per supervisor
php artisan horizon:pause-supervisor supervisor-1
php artisan horizon:continue-supervisor supervisor-1

# Stato
php artisan horizon:status
php artisan horizon:supervisor-status supervisor-1

# Terminazione graceful
php artisan horizon:terminate

Sviluppo locale: auto-restart

npm install --save-dev chokidar
php artisan horizon:listen

# In Docker/Vagrant
php artisan horizon:listen --poll

Supervisor in produzione

Installazione:
sudo apt-get install supervisor
Configurazione (/etc/supervisor/conf.d/horizon.conf):
[program:horizon]
process_name=%(program_name)s
command=php /home/forge/example.com/artisan horizon
autostart=true
autorestart=true
user=forge
redirect_stderr=true
stdout_logfile=/home/forge/example.com/horizon.log
stopwaitsecs=3600
Imposta stopwaitsecs più alto del job più lungo.
Avvio:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start horizon
Al deploy, riavvia Horizon:
php artisan horizon:terminate
Con Supervisor autostart=true/autorestart=true, si riavvia da solo.

Gestione dei job

Tag

Horizon aggiunge automaticamente tag ai job in base ai modelli Eloquent che ricevono.
// Video (id=1) → tag "App\Models\Video:1"
RenderVideo::dispatch(Video::find(1));
Tag manuali via tags():
class RenderVideo implements ShouldQueue
{
    public function tags(): array
    {
        return ['render', 'video:'.$this->video->id];
    }
}
Nei listener l’evento viene passato a tags().
class SendRenderNotifications implements ShouldQueue
{
    public function tags(VideoRendered $event): array
    {
        return ['video:'.$event->video->id];
    }
}

Silenziare job

In config/horizon.php:
'silenced' => [
    App\Jobs\ProcessPodcast::class,
],

'silenced_tags' => [
    'notifications',
],
Oppure implementa Silenced.
use Laravel\Horizon\Contracts\Silenced;

class ProcessPodcast implements ShouldQueue, Silenced
{
    use Queueable;
}

Metriche e monitoraggio

Pianifica gli snapshot:
use Illuminate\Support\Facades\Schedule;

Schedule::command('horizon:snapshot')->everyFiveMinutes();
Per cancellare le metriche:
php artisan horizon:clear-metrics

Notifiche dei fallimenti

Notifiche per attese troppo lunghe. In boot() di HorizonServiceProvider:
use Laravel\Horizon\Horizon;

public function boot(): void
{
    parent::boot();

    Horizon::routeMailNotificationsTo('[email protected]');
    Horizon::routeSlackNotificationsTo('slack-webhook-url', '#ops');
    Horizon::routeSmsNotificationsTo('15556667777');
}

Soglie di attesa

In config/horizon.php:
'waits' => [
    'redis:critical' => 30,
    'redis:default' => 60,
    'redis:batch' => 120,
],
0 disabilita.

Job falliti

# Elimina uno specifico
php artisan horizon:forget 5

# Elimina tutti i falliti
php artisan horizon:forget --all
Svuotare code:
php artisan horizon:clear
php artisan horizon:clear --queue=emails

Aggiornamento

Consulta sempre la Guida all’upgrade.

Pagine correlate

Code e job

Le basi delle code Laravel: creazione, dispatch, batch e gestione fallimenti.

Redis

Configurazione e uso di Redis, backend necessario per Horizon.
Ultima modifica il 13 luglio 2026