# Dashboard operations

> Job-state tabs, per-queue drill-down, search, delete, empty queue and Perform Now.

Source: https://boring-observability.dev/skyline/docs/dashboard-operations
Section: Queue control — Skyline for Laravel documentation
Updated: 2026-07-13

---

The Skyline dashboard adds the operations Horizon's leaves out: run a delayed or retrying job immediately, open a queue and read the exact jobs waiting inside it, search by job class name, delete a job, and empty a queue — each guarded in the backend, not just in the UI. None of it requires configuration.

Horizon's dashboard is a very good window. Skyline's is a control room: the same information, plus the buttons to act on it.

## Job-state tabs

Skyline replaces the scattered job lists with one tabbed **Jobs** view, available both globally and scoped to a single queue:

| Tab | Shows | Actions |
| --- | --- | --- |
| **In Progress** | Reserved jobs a worker is executing right now, with a live `HH:MM:SS` running-for duration. | — |
| **Pending** | Jobs waiting to be picked up. Reserved jobs stay visible, badged *Running*. | Delete |
| **Scheduled** | Delayed jobs that have *never* been attempted, with their absolute next-run time. | Perform Now, Delete |
| **Retries** | Jobs released back to the queue after a failure, waiting out a backoff window. | Perform Now, Delete |
| **Completed** | Recently finished jobs with runtime and timestamps. | — |
| **Failed** | Failed jobs with the exception and a link to the full failure detail. | Retry |

Splitting **Scheduled** from **Retries** is the useful part. Horizon lumps both into one undifferentiated list of delayed jobs, which means a queue that is quietly failing and backing off looks identical to one with healthy scheduled work in it. Skyline splits them on attempt count: never attempted is *scheduled*, released-after-failure is a *retry*.

## Perform Now

A delayed or retrying job sits idle until its available-at time arrives. When you have just deployed the fix, waiting out a fifteen-minute backoff window is pure downtime. **Perform Now** triggers the job immediately, from the Scheduled and Retries tabs and from the job's detail page.

## Per-queue drill-down

Click any queue on the dashboard to open the same tab set scoped to that queue — the exact jobs waiting inside it, in order. This answers the question the workload panel raises and never resolves: *what* is in the backlog?

## Search by job name

Every job list accepts a search on the job class name, matched as a **case-insensitive substring**. So `podcast` finds `App\Jobs\ProcessPodcast`. Search works across the pending, completed, retried and failed views.

## Deleting jobs and emptying a queue

Skyline can remove jobs from a queue, from a per-job Delete button on the pending, scheduled and retries lists and on the job detail page — or wholesale, with **Empty queue**.

Both are guarded, in the UI and in the backend:

- Every destructive action goes through a confirmation modal.
- Only **pending** and **delayed** jobs can be deleted. A job a worker has already reserved is not deletable — the request is rejected with `422` rather than leaving a half-executed job behind.
- Completed, silenced and failed jobs get no Delete button. They are historical records, not queue entries; a failed job is removed by retrying it or by the usual trimming.
- Per-job deletion requires a Redis queue connection. Other drivers are rejected with `422`.
- If a job is picked up by a worker between the moment you click and the moment the delete lands, the request fails with `409` rather than silently doing nothing.

> **Unique jobs are handled**
>
> Deleting a job or emptying a queue releases the `ShouldBeUnique` lock of every job removed. Without that, a deleted unique job would leave its lock behind and silently block all future dispatches of the same job. See [Unique job locks](https://boring-observability.dev/skyline/docs/unique-job-locks).

## Previous-attempt failure reasons

When a job throws or times out but still has retries left, that failure reason is normally lost — you see only the exception from the final attempt, long after the interesting one. Skyline records each attempt's failure and shows the history in a **Previous Attempts** panel on the job's page, for both recent and failed jobs.

Each entry captures the attempt number, whether it was an exception or a timeout, the timestamp, and — for exceptions — the full stack trace. Because a stack trace is not small, only the most recent `attempt_exceptions` entries are retained per job; the default is `1`. See [Configuration](https://boring-observability.dev/skyline/docs/configuration#attempt-exceptions).

## Honest wait times

The dashboard reports two different numbers that Horizon conflates: the **actual** current delay on a queue, measured from the oldest job waiting in it, and the **expected** wait time, derived from a moving average of recent jobs. They answer different questions and they disagree in exactly the moments that matter. See [Metrics & trends](https://boring-observability.dev/skyline/docs/metrics-and-trends#wait-time).


## Common questions

### How do I run a delayed or retrying Laravel job immediately?

Use Perform Now, from the Scheduled and Retries tabs or from the job's detail page. It triggers the job at once instead of waiting out its backoff window — which is exactly what you want the moment you have deployed the fix.

### Can I delete a job a worker is already running?

No. Only pending and delayed jobs can be deleted; a reserved job is rejected with a 422 rather than leaving a half-executed job behind. If a worker picks the job up between your click and the delete landing, the request fails with a 409 rather than silently doing nothing.

### What is the difference between the Scheduled and Retries tabs?

Skyline splits delayed jobs on attempt count: never attempted is scheduled, released-after-failure is a retry. Horizon lumps both into one undifferentiated list, which means a queue that is quietly failing and backing off looks identical to one with healthy scheduled work in it.
