Passer au contenu principal

Qu’est-ce que Horizon

Laravel Horizon est un tableau de bord dédié aux queues Redis de Laravel. Débit des jobs, temps d’exécution, échecs — le tout en temps réel, avec une configuration des workers gérée par code.
Horizon complète les fonctionnalités de base. Lisez d’abord Queues et jobs et Redis est obligatoire en backend.

Installation

Horizon exige Redis comme backend. Vérifiez que QUEUE_CONNECTION (config/queue.php) vaut redis. Redis Cluster n’est pas pris en charge.
Installez via Composer.
composer require laravel/horizon
Publiez les fichiers.
php artisan horizon:install
Cela génère config/horizon.php et app/Providers/HorizonServiceProvider.php.

Configuration

config/horizon.php

Ce fichier gère la configuration des workers. Le cœur est l’option 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' => [
            // Les autres valeurs sont héritées de defaults
            'maxProcesses' => 3,
        ],
    ],
],
Horizon utilise en interne une connexion Redis nommée horizon. Ne réutilisez pas ce nom dans config/database.php.

Superviseurs

Un environnement peut contenir plusieurs « superviseurs ». Un superviseur groupe des workers avec ses propres files, stratégie d’équilibrage et nombre de processus.

Defaults

Utilisez defaults pour partager des valeurs entre tous les superviseurs.
'defaults' => [
    'supervisor-1' => [
        'connection' => 'redis',
        'queue' => ['default'],
        'balance' => 'auto',
        'tries' => 1,
        'timeout' => 60,
        'maxProcesses' => 1,
    ],
],

Mode maintenance

Par défaut Horizon ne traite pas les jobs en maintenance. Forcez avec force.
'environments' => [
    'production' => [
        'supervisor-1' => [
            'force' => true,
        ],
    ],
],

Tentatives max

'environments' => [
    'production' => [
        'supervisor-1' => [
            'tries' => 10,
        ],
    ],
],
0 = illimité.

Timeout

'environments' => [
    'production' => [
        'supervisor-1' => [
            'timeout' => 60,
        ],
    ],
],
Définissez timeout quelques secondes en dessous de retry_after (config/queue.php). En balance auto, les jobs dépassant ce délai peuvent être tués.

Backoff

Attente entre les tentatives.
// Fixe
'backoff' => 10,

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

Stratégies d’équilibrage

Trois stratégies :
Ajuste automatiquement le nombre de workers selon la charge. minProcesses et maxProcesses fixent les bornes.
'supervisor-1' => [
    'balance' => 'auto',
    'autoScalingStrategy' => 'time', // ou 'size'
    'minProcesses' => 1,
    'maxProcesses' => 10,
    'balanceMaxShift' => 1,
    'balanceCooldown' => 3,
],
  • time : temps estimé pour vider la file
  • size : nombre de jobs
En auto, l’ordre des files n’indique pas la priorité. Utilisez plusieurs superviseurs pour forcer la priorité.
Nombre fixe de workers réparti à parts égales.
'supervisor-1' => [
    'balance' => 'simple',
    'processes' => 10,
    'queue' => ['default', 'notifications'],
],
Ici, 5 processus par file.
Ordre strict, comme la queue par défaut, mais avec scaling selon l’accumulation.
'supervisor-1' => [
    'balance' => false,
    'queue' => ['default', 'notifications'],
    'minProcesses' => 1,
    'maxProcesses' => 10,
],
Les jobs default passent toujours avant notifications.

Autorisation du dashboard

Le dashboard est accessible sur /horizon. En local, tout le monde y accède ; en production, restreignez via une gate. Éditez la méthode gate() de 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]',
        ]);
    });
}
Sans authentification (IP filtering, etc.), rendez le paramètre optionnel.
Gate::define('viewHorizon', function (User $user = null) {
    // Protégé par IP, etc.
    return true;
});

Démarrer Horizon

Commandes

# Démarrer
php artisan horizon

# Pause / reprise
php artisan horizon:pause
php artisan horizon:continue

# Pause / reprise d'un superviseur
php artisan horizon:pause-supervisor supervisor-1
php artisan horizon:continue-supervisor supervisor-1

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

# Arrêt gracieux
php artisan horizon:terminate

Local : redémarrage auto

horizon:listen redémarre Horizon quand un fichier change.
npm install --save-dev chokidar
php artisan horizon:listen

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

Supervisor en production

Faites tourner Horizon en continu avec Supervisor.

Installation

sudo apt-get install supervisor

Config

Créez /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
stopwaitsecs doit être supérieur à la durée du plus long job. Sinon Supervisor l’interromprait de force.

Démarrage

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start horizon

Déploiement

À chaque déploiement, redémarrez Horizon pour appliquer les changements.
php artisan horizon:terminate
Avec Supervisor en autostart=true / autorestart=true, il redémarre automatiquement.

Gestion des jobs

Tags

Horizon détecte automatiquement les modèles Eloquent liés à un job et pose des tags.
// Job recevant Video(id=1) → tag automatique "App\Models\Video:1"
RenderVideo::dispatch(Video::find(1));
Personnalisez avec tags().
class RenderVideo implements ShouldQueue
{
    /**
     * @return array<int, string>
     */
    public function tags(): array
    {
        return ['render', 'video:'.$this->video->id];
    }
}
Pour un event listener, l’instance de l’événement est passée à tags().
class SendRenderNotifications implements ShouldQueue
{
    public function tags(VideoRendered $event): array
    {
        return ['video:'.$event->video->id];
    }
}

Silence

Masquer certains jobs de la liste « Completed Jobs » via config/horizon.php.
'silenced' => [
    App\Jobs\ProcessPodcast::class,
],

// Par tag
'silenced_tags' => [
    'notifications',
],
Ou via l’interface Silenced.
use Laravel\Horizon\Contracts\Silenced;

class ProcessPodcast implements ShouldQueue, Silenced
{
    use Queueable;
    // ...
}

Métriques et supervision

Le dashboard des métriques affiche débit et durée des jobs/files. Planifiez des snapshots réguliers.
// routes/console.php
use Illuminate\Support\Facades\Schedule;

Schedule::command('horizon:snapshot')->everyFiveMinutes();
Réinitialiser les métriques :
php artisan horizon:clear-metrics

Notifications d’échec

Recevez des notifications quand une file s’allonge. Dans boot() de HorizonServiceProvider.
use Laravel\Horizon\Horizon;

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

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

Seuils d’attente

Réglez waits dans config/horizon.php.
'waits' => [
    'redis:critical' => 30,  // > 30 s → notification
    'redis:default' => 60,
    'redis:batch' => 120,
],
0 désactive la notification.

Gestion des jobs échoués

Suppression par ID ou UUID.
# Un job échoué précis
php artisan horizon:forget 5

# Tous
php artisan horizon:forget --all
Purger une file :
# File par défaut
php artisan horizon:clear

# File précise
php artisan horizon:clear --queue=emails

Mise à jour

Consultez toujours le guide de mise à jour avant une montée de version majeure.

Pages associées

Queues et jobs

Bases des queues Laravel : création, dispatch, batch, échecs.

Redis

Configuration et usage de Redis, backend requis par Horizon.
Dernière modification le 13 juillet 2026