Skyline

Getting started

Configuration

Every config key Skyline adds on top of the stock config/horizon.php.

Skyline reads the same config/horizon.php as Horizon. Every upstream option — path, prefix, middleware, waits, silenced, environments and the rest — behaves exactly as documented in the Horizon documentation. This page covers only the keys Skyline adds.

All of them have working defaults. A Horizon config file copied across unchanged is a valid Skyline config file.

Reference

Key Env Default Purpose
log_channel HORIZON_LOG_CHANNEL null Log channel that receives job lifecycle events. null uses the application default channel.
worker_output HORIZON_WORKER_OUTPUT 'cli' 'cli' or 'json'. See JSON worker output.
attempt_exceptions 1 How many previous-attempt failure reasons to retain per job. 0 disables recording.
trim.delayed 10080 Minutes to retain delayed-job tracking data (7 days).
metrics.ema_alpha 0.05 Smoothing factor for the runtime and wait-time moving averages. Between 0 and 1.
metrics.snapshot_lock 300 Seconds a horizon:snapshot lock is held, to de-duplicate concurrent snapshots. Not written to the published file.
trends.interval 15 Minutes per trend bucket, and the workload sampling cadence.
trends.retention 24 Hours of trend history to keep and display.
environments.*.*.queueWeights [] Per-supervisor map of queue name to weight. Only valid when balance is false.

log_channel

Routes Skyline's job lifecycle log lines to a dedicated channel, so a full end-to-end job trace does not drown your application log. Leave it null to use the default channel.

'log_channel' => env('HORIZON_LOG_CHANNEL'),

Because each event is emitted at a level appropriate to its severity, the channel's own log level is the volume dial: point it at a channel with level error to see only failures, or debug for a full trace of every job. The full event list is on the Job lifecycle logging page.

worker_output

Each worker writes one line per job to its output. The default 'cli' format is the human-readable table you see in the terminal; 'json' emits one structured object per line for a log pipeline to ingest.

'worker_output' => env('HORIZON_WORKER_OUTPUT', 'cli'),
Laravel 11+

JSON output relies on the framework's structured worker output, which exists on Laravel 11 and later. On earlier versions the setting is simply never consulted and output stays in CLI format — no error is raised.

attempt_exceptions

When a job throws or times out but still has retries left, Skyline records why that attempt failed and shows the history under a Previous Attempts panel on the job's dashboard page. Because each entry can carry a full stack trace, the number retained per job is capped.

'attempt_exceptions' => 1,

The default of 1 keeps only the most recent failure reason. Raise it to retain more history — the oldest entries beyond the limit are dropped — or set it to 0 to turn the feature off entirely.

trim.delayed

Skyline indexes delayed jobs so the Scheduled and Retries views can show them with their real next-run time. That index is trimmed on the same principle as Horizon's other retention settings:

'trim' => [
    'recent' => 60,
    'pending' => 60,
    'completed' => 60,
    'recent_failed' => 10080,
    'failed' => 10080,
    'monitored' => 10080,
    'delayed' => 10080,
],

delayed is the Skyline addition; the rest are upstream. The value is in minutes, and the default of 10080 is seven days. Trimming runs periodically from the php artisan horizon master process, so it requires no separate scheduled command.

metrics

'metrics' => [
    'trim_snapshots' => [
        'job' => 24,
        'queue' => 24,
    ],

    'ema_alpha' => 0.05,
],

ema_alpha is the smoothing factor of the exponential moving average behind Skyline's runtime and wait-time estimates. It must sit between 0 and 1. Lower values produce a stable average that shrugs off outliers; higher values react faster to a genuine change in job duration. The default of 0.05 is deliberately conservative — a single pathological job should not move the estimate much.

Configures the time-series behind the dashboard's workload, wait-time and failure trend charts.

'trends' => [
    'interval' => 15,
    'retention' => 24,
],

interval is the size of each bucket in minutes, and doubles as the sampling cadence for the workload and wait series. retention is how many hours of history to keep and display. Together they set the number of points on the chart: the defaults give 96 buckets across 24 hours. Shortening the interval gives a finer chart at the cost of more Redis keys and a busier render.

Trends need the master process

Workload and wait samples are taken from the php artisan horizon master process loop, not from a scheduled command. Failure counts are recorded as jobs fail. If the master process is not running, no workload samples are recorded for that period — but nothing else breaks.

queueWeights

A per-supervisor map that turns strict left-to-right queue priority into a proportional policy. It is only valid when that supervisor runs with 'balance' => false.

'supervisor-1' => [
    'connection' => 'redis',
    'queue' => ['high', 'default', 'low'],
    'balance' => false,
    'queueWeights' => [
        'high' => 3,
        'default' => 2,
        // 'low' is omitted, so it keeps the default weight of 1
    ],
],

See Weighted queues for the semantics, the exception raised when it is combined with a balancing strategy, and the block_for notes.

Queue control, not just queue monitoring.

Skyline is a drop-in replacement for Laravel Horizon that lets you act on what you see — pause a queue, jump a job to the front, drain a backlog.

Sign up for early access