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

# Job States

> The eight unified states that every job can be in, and how they map from Celery.

Sluice uses a normalized state model with eight states. This abstraction exists because the architecture supports multiple job queue frameworks — Celery today, BullMQ and Sidekiq in the future — each with different native state machines.

## Unified states

| State       | Description                                                     | Celery equivalent     |
| ----------- | --------------------------------------------------------------- | --------------------- |
| `unknown`   | No information about this job. It may exist, or it may not.     | `PENDING`             |
| `queued`    | Job has been received by a worker but hasn't started executing. | `RECEIVED`            |
| `scheduled` | Job is scheduled for future execution (ETA/countdown).          | ETA tasks in broker   |
| `active`    | Job is currently executing on a worker.                         | `STARTED`             |
| `completed` | Job finished successfully.                                      | `SUCCESS`             |
| `failed`    | Job raised an exception or was rejected.                        | `FAILURE`, `REJECTED` |
| `retrying`  | Job failed and is waiting to be retried.                        | `RETRY`               |
| `cancelled` | Job was revoked by the user or system.                          | `REVOKED`             |

## The PENDING problem

Celery's `PENDING` state is uniquely confusing. The Celery documentation itself notes it would be "better named 'unknown'" because it's the default state for **any task ID** — including ones that don't exist.

If you query Celery for the state of task `abc123` and get `PENDING`, that could mean:

* The task was dispatched and is waiting in the queue
* The task ID is a typo and no such task was ever created
* The task completed hours ago and the result backend has already expired the record

Sluice addresses this by tracking the `task-sent` event (enabled by `task_send_sent_event=True`). When Sluice sees a `task-sent` event, it creates the job record with state `queued`. A task that Sluice has never seen remains `unknown` — and the dashboard makes the distinction clear.

## State transitions

Jobs move through states in a predictable flow:

```mermaid theme={null}
stateDiagram-v2
  unknown --> queued
  queued --> scheduled
  queued --> active
  scheduled --> active
  active --> completed
  active --> failed
  failed --> retrying
  retrying --> queued : retry
  queued --> cancelled
  active --> cancelled
  failed --> [*] : max retries
  completed --> [*]
  cancelled --> [*]
```

Every transition is recorded in the job's state history, which you can view in the Job Detail page or retrieve via the API.

## Management actions by state

Not every state allows every action. The available management actions depend on the job's current state:

| Action     | Allowed states                                         |
| ---------- | ------------------------------------------------------ |
| **Retry**  | `failed`, `cancelled`                                  |
| **Revoke** | `active`, `queued`, `scheduled`, `retrying`, `unknown` |

Attempting an action on a job in a disallowed state returns a `400` error with a descriptive message.
