← Files TemporalARCHIVED FILE

skills/temporal-ops/references/ops/workflow-health.md

12.8 KB · Oct 3, 2026 · 06:08 UTC

↓ Download file

# Workflow Health Queries

Data-plane commands for **finding** unhealthy Workflow Executions.
Backend-agnostic (works on Temporal Cloud and self-hosted).

> **Scope.** This file covers *locating* stuck/hung/failed workflows.
> To *diagnose why* a specific workflow is stuck, see `../triage/workflow-stuck.md`.

---

## 1. List Filter fundamentals

`temporal workflow list` accepts an optional `--query` (`-q`) flag whose value is an SQL-like List Filter string.

### Supported operators

`=, !=, >, >=, <, <=` | `AND, OR, ()` | `BETWEEN ... AND` | `IN` | `STARTS_WITH`

Additional filter expressions: `IS NULL`, `IS NOT NULL`

> **ORDER BY is not supported in Temporal Cloud.**
> The default ordering is `ClosedTime DESC NULL FIRST`, `StartTime DESC`.

### Key Search Attributes for health queries

All of the following are default (built-in) Search Attributes:

| Attribute | Type | Notes |
|-----------|------|-------|
| `ExecutionStatus` | Keyword | Current state. Values: `Running`, `Completed`, `Failed`, `Canceled`, `Terminated`, `ContinuedAsNew`, `TimedOut` |
| `WorkflowType` | Keyword | The type of Workflow |
| `WorkflowId` | Keyword | Identifies the Workflow Execution |
| `TaskQueue` | Keyword | Task Queue used by Workflow Execution |
| `StartTime` | Datetime | Time the Workflow Execution started |
| `CloseTime` | Datetime | Time the Workflow Execution completed (closed workflows only) |
| `ExecutionTime` | Datetime | Actual begin time; differs from `StartTime` for cron/retry |
| `ExecutionDuration` | Int | Time to run in nanoseconds (closed workflows only) |
| `HistoryLength` | Int | Event count (closed workflows only) |
| `HistorySizeBytes` | Long | Size of Event History |
| `StateTransitionCount` | Int | Number of state persists (closed workflows only) |

Search Attribute names are case sensitive.

Datetime attributes accept RFC3339Nano strings (e.g. `"2024-01-15T10:00:00Z"`) or epoch-nanosecond integers.

`ExecutionDuration` accepts nanosecond integers, Golang duration format, or `"hh:mm:ss"` format.

---

## 2. Listing workflows by status

### All running workflows

```
temporal workflow list \
    --query "ExecutionStatus = 'Running'"
```

### All failed workflows

```
temporal workflow list \
    --query "ExecutionStatus = 'Failed'"
```

### All timed-out workflows

```
temporal workflow list \
    --query "ExecutionStatus = 'TimedOut'"
```

### All terminated workflows

```
temporal workflow list \
    --query "ExecutionStatus = 'Terminated'"
```

### Non-running workflows (any closed status)

```
temporal workflow list \
    --query "ExecutionStatus != 'Running'"
```

---

## 3. Finding stuck/long-running workflows

### Running longer than a time threshold

Workflows that started more than 24 hours ago and are still running:

```
temporal workflow list \
    --query "ExecutionStatus = 'Running' AND StartTime < '2024-01-14T00:00:00Z'"
```

Replace the timestamp with the appropriate cutoff for your use case.

### Running workflows on a specific Task Queue

```
temporal workflow list \
    --query "ExecutionStatus = 'Running' AND TaskQueue = 'my-task-queue'"
```

### Running workflows of a specific type

```
temporal workflow list \
    --query "ExecutionStatus = 'Running' AND WorkflowType = 'MyWorkflow'"
```

### Combining conditions

```
temporal workflow list \
    --query "WorkflowType = 'OrderWorkflow' AND ExecutionStatus = 'Running' AND StartTime < '2024-01-14T00:00:00Z'"
```

### Workflows started in a time window

```
temporal workflow list \
    --query "StartTime BETWEEN '2024-01-01T00:00:00Z' AND '2024-01-02T00:00:00Z'"
```

### Matching Workflow IDs by prefix

```
temporal workflow list \
    --query "WorkflowId STARTS_WITH 'order-'"
```

`STARTS_WITH` is only available for Keyword Search Attributes.

---

## 4. Counting workflows

`temporal workflow count` returns a count of Workflow Executions regardless of execution state. Use `--query` to filter:

```
temporal workflow count \
    --query "ExecutionStatus = 'Running'"
```

```
temporal workflow count \
    --query "ExecutionStatus = 'Failed'"
```

```
temporal workflow count \
    --query "ExecutionStatus = 'Running' AND TaskQueue = 'my-task-queue'"
```

Use count to detect anomalies: a rising count of `Running` workflows with a stable `Failed` count may indicate workers are not processing tasks (check poller status below).

---

## 5. Describing a specific workflow

`temporal workflow describe` displays information about a specific Workflow Execution:

```
temporal workflow describe \
    --workflow-id YourWorkflowId
```

Key flags:

| Flag | Description |
|------|-------------|
| `--workflow-id`, `-w` | **(required)** Workflow ID |
| `--run-id`, `-r` | Run ID (optional, defaults to latest run) |
| `--reset-points` | Show auto-reset points only |
| `--raw` | Print properties without format changes |

The output includes execution status, start/close times, task queue, workflow type, search attributes, and pending activities/child workflows.

### Viewing Event History

`temporal workflow show` displays the full Event History:

```
temporal workflow show \
    --workflow-id YourWorkflowId
```

Key flags:

| Flag | Description |
|------|-------------|
| `--workflow-id`, `-w` | **(required)** Workflow ID |
| `--run-id`, `-r` | Run ID |
| `--follow`, `-f` | Follow progress in real time (not for JSON output) |
| `--reverse` | Fetch newest events first (cannot combine with `--follow`) |
| `--detailed` | Display events as detailed sections |
| `--output json` | JSON output (usable for SDK replay) |

Export history for replay:

```
temporal workflow show \
    --workflow-id YourWorkflowId \
    --output json
```

---

## 6. Stack trace

Get the current stack trace of a running Workflow's threads/routines:

```
temporal workflow stack \
    --workflow-id YourWorkflowId
```

This performs a `__stack_trace`-type Query on the Workflow Execution.

Flags:

| Flag | Description |
|------|-------------|
| `--workflow-id`, `-w` | **(required)** Workflow ID |
| `--run-id`, `-r` | Run ID |
| `--reject-condition` | Reject based on Workflow state. Values: `not_open`, `not_completed_cleanly` |

---

## 7. Task Queue poller status

`temporal task-queue describe` displays active Workers that have recently polled a Task Queue.

```
temporal task-queue describe \
    --task-queue YourTaskQueue
```

**Interpreting poller results:**

- The Temporal Server records each poll request time.
- A `LastAccessTime` over one minute may indicate the Worker is at capacity or has shut down.
- Workers are removed if 5 minutes have passed since the last poll request.

### Workflow vs. Activity pollers

Workflow and Activity polling use separate Task Queues. Specify the type to check Activity pollers:

```
temporal task-queue describe \
    --task-queue YourTaskQueue \
    --task-queue-type "activity"
```

The `--task-queue-type` flag accepts: `workflow`, `activity`, `nexus`. If not specified, all types are reported.

### Backlog statistics

The describe output includes the following statistics:

| Statistic | Description |
|-----------|-------------|
| `ApproximateBacklogCount` | Approximate tasks backlogged. May count expired tasks but eventually converges. |
| `ApproximateBacklogAge` | Approximate age of the oldest backlogged task (seconds), based on creation time. |
| `TasksAddRate` | Approximate tasks added per second, averaged over the last 30 seconds. Includes sync-matched tasks. |
| `TasksDispatchRate` | Approximate tasks dispatched per second, averaged over the last 30 seconds. Includes sync-matched tasks. |
| `BacklogIncreaseRate` | Approximate rate of backlog growth (positive) or shrinkage (negative), in tasks per second. Roughly `TasksAddRate - TasksDispatchRate`. |

> **Note:** `TasksAddRate` and `TasksDispatchRate` may differ from actual rates because eagerly dispatched or sticky tasks are not counted. The derived `BacklogIncreaseRate` is accurate for backlogs older than a few seconds.

To disable statistics and show only poller info, use `--disable-stats`.

### What to look for

- **No pollers**: No Workers are running (or recently running) for this Task Queue. Workflows on this queue will not make progress.
- **Stale `LastAccessTime`**: Workers may be overloaded or shutting down.
- **Growing `ApproximateBacklogCount` / positive `BacklogIncreaseRate`**: Workers cannot keep up with the incoming task rate. Scale up Workers or investigate slow activities.

---

## 8. Workflow tracing

Display progress of a Workflow Execution and its child workflows in real time:

```
temporal workflow trace \
    --workflow-id YourWorkflowId
```

Key flags:

| Flag | Description |
|------|-------------|
| `--workflow-id`, `-w` | **(required)** Workflow ID |
| `--depth` | Depth for child Workflow fetches. `-1` fetches all depths. |
| `--fold` | Fold away child Workflows with specified statuses. Values: `running`, `completed`, `failed`, `canceled`, `terminated`, `timedout`, `continueasnew`. |
| `--no-fold` | Disable folding; fetch and display all child Workflows within depth. |
| `--concurrency` | Number of Workflow Histories to fetch concurrently. |

---

## 9. Pagination and output control

### Limiting results

```
temporal workflow list \
    --query "ExecutionStatus = 'Running'" \
    --limit 50
```

### Page size

```
temporal workflow list \
    --query "ExecutionStatus = 'Running'" \
    --page-size 100
```

### JSON output

Use `--output json` or `--output jsonl` on any command for machine-readable output.

### Archived workflows

```
temporal workflow list --archived
```

This is an experimental feature.

---

## 10. Common health-check patterns

### Pattern: "Are any workflows stuck?"

```bash
# Count running workflows that started more than 1 hour ago
temporal workflow count \
    --query "ExecutionStatus = 'Running' AND StartTime < '2024-01-15T09:00:00Z'"

# If count > 0, list them
temporal workflow list \
    --query "ExecutionStatus = 'Running' AND StartTime < '2024-01-15T09:00:00Z'" \
    --limit 20
```

### Pattern: "Are workers healthy?"

```bash
# Check pollers on the task queue
temporal task-queue describe \
    --task-queue my-task-queue

# Check activity pollers separately
temporal task-queue describe \
    --task-queue my-task-queue \
    --task-queue-type activity
```

Look for: active pollers present, `LastAccessTime` within the last minute, no growing backlog.

### Pattern: "What failed recently?"

```bash
temporal workflow list \
    --query "ExecutionStatus = 'Failed' AND CloseTime > '2024-01-15T00:00:00Z'"

temporal workflow count \
    --query "ExecutionStatus = 'Failed' AND CloseTime > '2024-01-15T00:00:00Z'"
```

To break failures down by Workflow Type, add a `WorkflowType` filter to the same query. Run a count per type across your known types:

```bash
temporal workflow count \
    --query "ExecutionStatus = 'Failed' AND WorkflowType = '<YourWorkflowType>'"
```

This identifies which Workflow Type is contributing the most failures rather than returning a flat list. `GROUP BY` in the Count API only supports grouping by `ExecutionStatus`, not by `WorkflowType` or other attributes — use per-type filtered counts instead.

### Pattern: "Workflows approaching history limits"

The server terminates a Workflow Execution when its Event History exceeds 51,200 events, contains more than 2,000 Updates, or more than 10,000 Signals. The `HistoryLength` Search Attribute surfaces the event count for running workflows.

```bash
temporal workflow list \
    --query "ExecutionStatus = 'Running' AND HistoryLength > 40000"
```

Long-lived workflows that grow history without using Continue-As-New will eventually hit these limits. This is common in agent-loop or orchestrator patterns. Workflows returned by this query need either Continue-As-New or a redesign to bound history growth.

### Pattern: "Drill into a specific stuck workflow"

```bash
# 1. Describe it (status, pending activities, search attributes)
temporal workflow describe --workflow-id <id>

# 2. View its event history (newest first)
temporal workflow show --workflow-id <id> --reverse

# 3. Get its stack trace (running workflows only)
temporal workflow stack --workflow-id <id>
```

For diagnosing *why* a workflow is stuck, see `../triage/workflow-stuck.md`.

---

## Quick reference: List Filter examples from docs

The following examples are taken directly from the docs:

```sql
WorkflowType = "main.YourWorkflowDefinition" and ExecutionStatus != "Running" and (StartTime > "2021-06-07T16:46:34.236-08:00" or CloseTime > "2021-06-07T16:46:34-08:00")
```

```sql
WorkflowId = '<workflow-id>'
```

```sql
WorkflowId = '<workflow-id>' or WorkflowId = '<another-workflow-id>'
```

```sql
WorkflowId IN ('<workflow-id>', '<another-workflow-id>')
```

```sql
WorkflowId = '<workflow-id>' and ExecutionStatus = 'Running'
```

```sql
WorkflowId = '<workflow-id>' and StartTime > '2021-08-22T15:04:05+00:00'
```

```sql
ExecutionTime between '2021-08-22T15:04:05+00:00' and '2021-08-28T15:04:05+00:00'
```

```sql
WorkflowType STARTS_WITH '<workflow-type-prefix>'
```

SHA-256: 1c2aabd8e9c22a632f8aa50c089812a10d903e56330576430c80d9016b87ccc7