> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel Horizon

> Explica cómo gestionar y monitorizar visualmente las colas de Redis con Laravel Horizon. Cubre el dashboard, las estrategias de balance, la configuración de Supervisor y las notificaciones.

## Qué es Horizon

[Laravel Horizon](https://github.com/laravel/horizon) es el **dashboard de monitorización específico para colas Redis** de Laravel. Visualiza en tiempo real la productividad, los tiempos de ejecución y los fallos de los jobs, y permite gestionar por código la configuración de los workers.

<Info>
  Horizon es un paquete que extiende la funcionalidad base de colas. Antes de continuar, familiarízate con lo básico de [Colas y jobs](/es/queues). Además, el backend debe ser necesariamente [Redis](/es/redis).
</Info>

```mermaid theme={null}
flowchart LR
    Browser["Navegador"] -->|"/horizon"| Dashboard["Dashboard<br>Horizon"]
    Dashboard -->|"Monitorización y control"| Horizon["Proceso<br>Horizon"]
    Horizon -->|"Gestión de jobs"| Redis["Cola<br>Redis"]
    Redis -->|"Obtener job"| Worker1["Worker 1"]
    Redis -->|"Obtener job"| Worker2["Worker 2"]
    Redis -->|"Obtener job"| Worker3["Worker 3"]
```

## Instalación

<Warning>
  Horizon utiliza Redis como backend de la cola. Verifica que `QUEUE_CONNECTION` en `config/queue.php` esté configurado como `redis`. Actualmente no soporta Redis Cluster.
</Warning>

Instala con Composer.

```shell theme={null}
composer require laravel/horizon
```

Tras la instalación, publica los assets y la configuración de Horizon.

```shell theme={null}
php artisan horizon:install
```

Este comando genera `config/horizon.php` y `app/Providers/HorizonServiceProvider.php`.

## Configuración

### Estructura de config/horizon.php

`config/horizon.php` es el archivo donde se gestiona toda la configuración de los workers. La opción central es `environments`.

```php theme={null}
'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' => [
            // El resto de valores se heredan de la sección defaults
            'maxProcesses' => 3,
        ],
    ],
],
```

<Info>
  Horizon usa internamente una conexión Redis llamada `horizon`. No utilices ese nombre para otras conexiones en `config/database.php`.
</Info>

### CSP nonce (Content Security Policy)

Si quieres, como parte de tu [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP), añadir el [atributo nonce](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/nonce) a las etiquetas `script` / `style` de las vistas de Horizon, usa el método `Horizon::cspNonce`. Como se debe asignar un nonce nuevo por petición, normalmente se invoca desde un middleware.

```php theme={null}
use Closure;
use Illuminate\Http\Request;
use Laravel\Horizon\Horizon;
use Symfony\Component\HttpFoundation\Response;

public function handle(Request $request, Closure $next): Response
{
    Horizon::cspNonce('csp-nonce');

    return $next($request);
}
```

Añade este middleware a la opción `middleware` de `config/horizon.php`.

```php theme={null}
'middleware' => [
    'web',
    App\Http\Middleware\AddHorizonCspNonce::class,
],
```

### Supervisores (Supervisor)

Cada entorno puede tener uno o varios «supervisores». Un supervisor es la unidad de gestión de un grupo de workers; en un mismo entorno pueden convivir varios supervisores con distintas colas, estrategias de balance y número de procesos.

### Valores por defecto

En la opción `defaults` puedes fijar valores por defecto que se aplican a todos los supervisores.

```php theme={null}
'defaults' => [
    'supervisor-1' => [
        'connection' => 'redis',
        'queue' => ['default'],
        'balance' => 'auto',
        'tries' => 1,
        'timeout' => 60,
        'maxProcesses' => 1,
    ],
],
```

### Modo mantenimiento

Cuando la aplicación está en modo mantenimiento, Horizon no procesa jobs por defecto. Para forzar el procesamiento usa la opción `force`.

```php theme={null}
'environments' => [
    'production' => [
        'supervisor-1' => [
            'force' => true,
        ],
    ],
],
```

### Número máximo de intentos de un job

```php theme={null}
'environments' => [
    'production' => [
        'supervisor-1' => [
            'tries' => 10,
        ],
    ],
],
```

Poner `tries` a `0` permite reintentos ilimitados.

### Timeout del job

```php theme={null}
'environments' => [
    'production' => [
        'supervisor-1' => [
            'timeout' => 60,
        ],
    ],
],
```

<Warning>
  Configura `timeout` unos segundos menor que `retry_after` en `config/queue.php`. Además, la estrategia de balance `auto` puede terminar por la fuerza jobs que superen este valor.
</Warning>

### Backoff (tiempo de espera antes de reintentar)

Indica los segundos de espera antes de reintentar tras una excepción.

```php theme={null}
// Valor fijo
'backoff' => 10,

// Escalonado (backoff exponencial)
'backoff' => [1, 5, 10],
```

### Otras opciones del worker

Además de `tries`, `timeout` y `backoff`, cada supervisor admite opciones que controlan el comportamiento del proceso worker y el momento de reinicio automático. Reiniciar periódicamente los procesos de larga duración es una buena práctica para prevenir fugas de memoria.

```php theme={null}
'environments' => [
    'production' => [
        'supervisor-1' => [
            // ...
            'memory' => 128,
            'maxJobs' => 1000,
            'maxTime' => 3600,
            'sleep' => 3,
            'rest' => 0,
            'nice' => 0,
        ],
    ],
],
```

* `memory` — cantidad máxima de memoria (MB) que puede consumir un worker antes de reiniciarse. Por defecto `128`.
* `maxJobs` — número de jobs a procesar antes del reinicio. `0` significa sin límite. Por defecto `0`.
* `maxTime` — segundos que puede estar corriendo un worker antes del reinicio. `0` significa sin reinicio por tiempo. Por defecto `0`.
* `sleep` — segundos de espera hasta el siguiente polling cuando no hay jobs. Por defecto `3`.
* `rest` — segundos de pausa entre procesamiento de jobs. Por defecto `0`.
* `nice` — prioridad («niceness») del proceso worker. Cuanto más alto, menor prioridad. Por defecto `0`.

## Estrategias de balance

Horizon dispone de tres estrategias de balance de workers.

<AccordionGroup>
  <Accordion title="auto (por defecto)">
    Ajusta automáticamente el número de workers según la carga de la cola. Indica el rango con `minProcesses` y `maxProcesses`.

    ```php theme={null}
    'supervisor-1' => [
        'balance' => 'auto',
        'autoScalingStrategy' => 'time', // o 'size'
        'minProcesses' => 1,
        'maxProcesses' => 10,
        'balanceMaxShift' => 1,
        'balanceCooldown' => 3,
    ],
    ```

    * `time` — escala según el tiempo estimado para vaciar la cola.
    * `size` — escala según el número de jobs en la cola.

    <Info>
      Con la estrategia `auto`, el orden de las colas no implica prioridad. Si necesitas forzar prioridades, utiliza varios supervisores.
    </Info>
  </Accordion>

  <Accordion title="simple">
    Fija el número de workers y los distribuye equitativamente entre las colas indicadas.

    ```php theme={null}
    'supervisor-1' => [
        'balance' => 'simple',
        'processes' => 10,
        'queue' => ['default', 'notifications'],
    ],
    ```

    En este ejemplo se asignan 5 procesos a `default` y otros 5 a `notifications`.
  </Accordion>

  <Accordion title="false (sin balance)">
    Prioriza estrictamente las colas en el orden enumerado. Se comporta como el sistema de colas por defecto de Laravel, pero escala el número de workers según el backlog.

    ```php theme={null}
    'supervisor-1' => [
        'balance' => false,
        'queue' => ['default', 'notifications'],
        'minProcesses' => 1,
        'maxProcesses' => 10,
    ],
    ```

    Los jobs de la cola `default` se procesan siempre antes que los de `notifications`.
  </Accordion>
</AccordionGroup>

## Autorización del dashboard

El dashboard de Horizon está en la ruta `/horizon`. En local es accesible por defecto para cualquiera, pero en **producción** debes restringir el acceso mediante una gate.

Edita el método `gate()` de `app/Providers/HorizonServiceProvider.php`.

```php theme={null}
use App\Models\User;
use Illuminate\Support\Facades\Gate;

protected function gate(): void
{
    Gate::define('viewHorizon', function (User $user) {
        return in_array($user->email, [
            'admin@example.com',
        ]);
    });
}
```

Si no requieres autenticación (por ejemplo, si proteges por IP), haz el argumento opcional.

```php theme={null}
Gate::define('viewHorizon', function (User $user = null) {
    // Cuando se restringe por dirección IP, etc.
    return true;
});
```

## Arrancar Horizon

### Comandos básicos

```shell theme={null}
# Arrancar
php artisan horizon

# Pausar / reanudar
php artisan horizon:pause
php artisan horizon:continue

# Pausar / reanudar un supervisor concreto
php artisan horizon:pause-supervisor supervisor-1
php artisan horizon:continue-supervisor supervisor-1

# Comprobar estado
php artisan horizon:status
php artisan horizon:supervisor-status supervisor-1

# Apagado ordenado
php artisan horizon:terminate
```

### Desarrollo local: reinicio automático

Para reiniciar Horizon automáticamente al detectar cambios en los archivos, usa `horizon:listen`.

```shell theme={null}
npm install --save-dev chokidar
php artisan horizon:listen

# En entornos Docker / Vagrant
php artisan horizon:listen --poll
```

### Ejecución permanente con Supervisor

En producción se mantiene Horizon en marcha permanente con Supervisor.

#### Instalar Supervisor

```shell theme={null}
sudo apt-get install supervisor
```

#### Crear el archivo de configuración

Crea `/etc/supervisor/conf.d/horizon.conf`.

```ini theme={null}
[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
```

<Warning>
  Configura `stopwaitsecs` con un valor mayor que la duración del job más largo. Si es demasiado bajo, Supervisor terminará los jobs a la fuerza.
</Warning>

#### Arrancar Supervisor

```shell theme={null}
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start horizon
```

#### En cada despliegue

Cada vez que despliegues código, reinicia Horizon para reflejar los cambios.

```shell theme={null}
php artisan horizon:terminate
```

Con `autostart=true` / `autorestart=true` en Supervisor, se reiniciará automáticamente tras el apagado.

## Gestión de jobs

### Etiquetas

Horizon detecta automáticamente los modelos Eloquent relacionados con un job y les asigna etiquetas.

```php theme={null}
// Un job que recibe un Video con id=1 → se etiqueta automáticamente como "App\Models\Video:1"
RenderVideo::dispatch(Video::find(1));
```

Para definir etiquetas manualmente, implementa el método `tags()`.

```php theme={null}
class RenderVideo implements ShouldQueue
{
    /**
     * @return array<int, string>
     */
    public function tags(): array
    {
        return ['render', 'video:'.$this->video->id];
    }
}
```

En listeners de eventos, la instancia del evento se pasa al método `tags()`.

```php theme={null}
class SendRenderNotifications implements ShouldQueue
{
    public function tags(VideoRendered $event): array
    {
        return ['video:'.$event->video->id];
    }
}
```

### Silenciado

Los jobs que no quieras que aparezcan en la lista de «jobs completados» del dashboard pueden silenciarse en `config/horizon.php`.

```php theme={null}
'silenced' => [
    App\Jobs\ProcessPodcast::class,
],

// Silenciar por etiqueta
'silenced_tags' => [
    'notifications',
],
```

También puedes implementar la interfaz `Silenced`.

```php theme={null}
use Laravel\Horizon\Contracts\Silenced;

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

## Métricas y monitorización

El dashboard de métricas de Horizon muestra el throughput y los tiempos de ejecución de jobs y colas. Programa la toma periódica de snapshots.

```php theme={null}
// routes/console.php
use Illuminate\Support\Facades\Schedule;

Schedule::command('horizon:snapshot')->everyFiveMinutes();
```

La opción `metrics.trim_snapshots` de `config/horizon.php` te permite configurar cuántos snapshots se conservan para las gráficas. Como este ajuste limita por número de entradas y no por antigüedad, el período efectivo de retención depende de la frecuencia con la que ejecutes `horizon:snapshot`.

```php theme={null}
'metrics' => [
    'trim_snapshots' => [
        'job' => 24,
        'queue' => 24,
    ],
],
```

Para borrar todos los datos de métricas:

```shell theme={null}
php artisan horizon:clear-metrics
```

## Notificaciones de fallo de jobs

Puedes recibir notificaciones cuando el tiempo de espera de la cola aumenta. Configúralo en el método `boot()` de `app/Providers/HorizonServiceProvider.php`.

```php theme={null}
use Laravel\Horizon\Horizon;

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

    Horizon::routeMailNotificationsTo('admin@example.com');
    Horizon::routeSlackNotificationsTo('slack-webhook-url', '#ops');
    Horizon::routeSmsNotificationsTo('15556667777');
}
```

### Umbrales de espera

En la opción `waits` de `config/horizon.php` configura los segundos de espera que disparan la notificación.

```php theme={null}
'waits' => [
    'redis:critical' => 30,  // Notifica a partir de 30 s de espera
    'redis:default' => 60,
    'redis:batch' => 120,
],
```

Al indicar `0` se desactiva la notificación para esa cola.

## Gestión de jobs fallidos

Puedes borrar jobs fallidos por su ID o UUID.

```shell theme={null}
# Borrar un job fallido concreto
php artisan horizon:forget 5

# Borrar todos los jobs fallidos
php artisan horizon:forget --all
```

Para vaciar todos los jobs de una cola:

```shell theme={null}
# Vaciar la cola por defecto
php artisan horizon:clear

# Vaciar una cola concreta
php artisan horizon:clear --queue=emails
```

## Actualización

Al actualizar a una nueva versión mayor de Horizon, consulta siempre la [guía de actualización](https://github.com/laravel/horizon/blob/master/UPGRADE.md).

## Páginas relacionadas

<CardGroup cols={2}>
  <Card title="Colas y jobs" href="/es/queues">
    Fundamentos de las colas de Laravel. Explica la creación, el despacho, el procesamiento por lotes y el manejo de fallos de los jobs.
  </Card>

  <Card title="Redis" href="/es/redis">
    Configuración y uso de Redis, necesario como backend de Horizon.
  </Card>
</CardGroup>


## Related topics

- [Caché](/es/cache.md)
- [Gestión de la compatibilidad de versiones de paquetes](/es/advanced/package-versioning.md)
- [Colas y jobs](/es/queues.md)
- [Laravel Sentinel — Investigación del middleware de protección de rutas](/es/blog/sentinel-introduction.md)
- [Actualización de Laravel — Abril de 2026](/es/blog/changelog/202604.md)
