# Queue health

> Read one bounded snapshot with a verdict and stable reason codes for exceeded budgets.

`Queue.health()` reports backlog depth, lease state, external waits, admission pressure, statistics,
and retention progress with a `healthy`, `degraded`, or `critical` verdict.

<Tabs items={["TypeScript", "Python", "Go"]}>
  <Tab value="TypeScript">

    ```ts
    const health = await queue.health();
    if (health.status.level !== "healthy") console.warn(health.status.reasons);
    ```

  </Tab>
  <Tab value="Python">

    ```python
    health = queue.health()
    if health["status"]["level"] != "healthy":
        print(health["status"]["reasons"])
    ```

  </Tab>
  <Tab value="Go">

    ```go
    health, err := queue.Health(ctx)
    status := health["status"].(map[string]any)
    if status["level"] != "healthy" {
        log.Print(status["reasons"])
    }
    ```

  </Tab>
</Tabs>

PostgreSQL reads correctness-sensitive values in one statement, so every exact count describes the
same instant at `capturedAt`. Lagging database statistics live under `observations`; when an
observation and an exact count disagree, the exact count wins.

## Bounded work, stable reasons

Live-state counts are exact. Unbounded terminal history and statistics buckets stop at explicit
caps and mark the result as a lower bound, so health polling does not become more expensive as a
database ages.

Critical reasons mean work is stopping now, such as an expired lease, overdue external wait, or
stalled promotion. Degraded reasons mean the queue still runs while maintenance or admission falls
behind. The reason codes are stable, so alerts can branch on them without parsing prose.

PostgreSQL owns the budgets and returns the applied values under `budgets`. Application sync seeds
defaults without replacing operator overrides, so TypeScript, Go, Python, the dashboard, and
`workhorse health --json` all use the same evaluation.

Every client decodes the database response into its language's `QueueHealth` type, preserving the
same reason codes and the `capped` lower-bound marker for operator tooling.

## Next

- [Operations](/docs/operations) — act on unhealthy queue state
- [Maintenance](/docs/maintenance) — understand the work health budgets watch
- [Dashboard](/docs/dashboard) — inspect reasons with operator context

---

Exact health fields, scan caps, budgets, and reason codes:
[architecture reference](https://github.com/stablemates/workhorse/blob/main/docs/architecture.md#read-models-and-health).
