# Pausing & resuming queues

> Pause every worker, one supervisor, or a single queue — then resume.

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

---

Skyline can stop queue processing at three levels of granularity — **everything**, **one supervisor**, or **a single queue** — and resume it when you are ready. Workers stop picking up new jobs; jobs already running finish, and new ones simply accumulate until you resume.

Pausing is the first thing you want during an incident: a downstream API is failing, a migration is halfway through, a bad deploy is churning through jobs. Horizon can only stop everything at once, which is a blunt instrument when one queue is the problem and the rest are healthy.

## Three levels

| Scope | How | Effect |
| --- | --- | --- |
| Everything | `php artisan horizon:pause` | Every worker on every supervisor stops picking up jobs. |
| One supervisor | `php artisan horizon:pause-supervisor {name}` | Only that supervisor's workers stop. |
| One queue | Dashboard, or the [HTTP API](https://boring-observability.dev/skyline/docs/api) | Workers keep serving their other queues and skip only the paused one. |

Each has a matching resume: `horizon:continue`, `horizon:continue-supervisor {name}`, and the Resume button (or a `DELETE` to the pause endpoint).

## Global and per-supervisor pause

These are the upstream Horizon commands, unchanged. They work by signalling the master supervisor process, so they take effect within a loop iteration and survive nothing — a restarted supervisor comes back unpaused.

```bash
# Stop everything, then resume
php artisan horizon:pause
php artisan horizon:continue

# Stop a single supervisor by name
php artisan horizon:pause-supervisor supervisor-1
php artisan horizon:continue-supervisor supervisor-1
```

Skyline adds pause and resume buttons for these to the dashboard, so an operator does not need shell access on a worker box to stop processing.

## Per-queue pause

Pausing a whole supervisor is a blunt instrument when one queue is the problem and the rest are healthy. Skyline exposes Pause and Resume per queue, straight from the dashboard.

A worker serving `high,default,low` whose `low` queue is paused keeps processing `high` and `default` at full speed and simply skips `low` when it comes around in the pickup loop. Autoscaling is aware of it too: the supervisor will not scale processes onto a paused queue.

Per-queue pause state lives in your **default cache store**, not in the worker's memory, which is what lets the dashboard, the supervisors and the workers all agree on it. It therefore survives a worker restart — a queue you paused stays paused until something resumes it.

> **Requirements**
>
> Per-queue pausing is built on Laravel's native queue-pause API, and needs a Laravel version that provides it. It also needs a shared cache store: the `array` and `null` stores cannot carry state between the dashboard and the worker processes, so they are rejected.
>
> When either requirement is unmet, Skyline detects it at runtime: the dashboard hides the per-queue Pause buttons and shows an explanatory banner, and the API endpoints respond `409 Conflict`. Nothing else is affected — global and per-supervisor pause keep working.

### Grouped queues

A non-balancing supervisor may serve a comma-joined group such as `high,default,low`. Skyline pauses and reports on the individual sub-queues: the group is shown as paused only when **every** sub-queue in it is paused. Pausing `low` alone leaves the group running.

### From the API

The dashboard buttons are backed by two endpoints, which you can call from a deploy script or an incident runbook:

```bash
# Pause the "exports" queue on the "redis" connection
curl -X POST https://example.com/horizon/api/queues/redis/exports/pause

# Resume it
curl -X DELETE https://example.com/horizon/api/queues/redis/exports/pause
```

Both return `204 No Content` on success, and `409 Conflict` when queue pausing is not supported in the environment.

> **The calls above are illustrative**
>
> These endpoints sit behind the same `viewHorizon` gate and `web` middleware as the dashboard itself, so a real script has to carry a session cookie and a CSRF token — a bare `curl` gets a redirect or a `419`, not a paused queue. See the [HTTP API](https://boring-observability.dev/skyline/docs/api) reference.

## Pausing is not draining

Pausing stops workers from *picking up* new jobs. It does not stop jobs already in flight — those run to completion — and it does not stop producers from dispatching. A paused queue keeps growing.

That is usually what you want during an incident, but it means a long pause on a busy queue has a cost you should plan for: the backlog you will have to work through on resume, and the Redis memory it occupies until then. If the jobs are genuinely unwanted rather than merely untimely, empty the queue instead — see [Dashboard operations](https://boring-observability.dev/skyline/docs/dashboard-operations).


## Common questions

### How do I pause a single Laravel queue?

Click Pause on the queue in the Skyline dashboard, or POST to /horizon/api/queues/{connection}/{queue}/pause. Workers serving that queue keep processing their other queues at full speed and simply skip the paused one. The pause state lives in your default cache store, so it survives a worker restart.

### Does pausing a queue stop jobs that are already running?

No. Pausing stops workers from picking up new jobs; jobs already in flight run to completion. It also does not stop producers from dispatching, so a paused queue keeps growing — plan for the backlog you will have to work through on resume, and the Redis memory it occupies until then.

### Why are the per-queue pause buttons missing from my dashboard?

Per-queue pausing is built on Laravel's native queue-pause API and needs a shared cache store. If the framework version does not provide the API, or the cache store is array or null — neither of which can carry state between the dashboard and the worker processes — Skyline hides the buttons, shows an explanatory banner, and the API endpoints respond 409 Conflict. Global and per-supervisor pause keep working.
