Priority
Priority configuration controls the ordering of workflow runs when concurrency limits create a backlog, using input-driven rules to promote or demote runs in the queue.
PriorityConfig
The PriorityConfig on WorkflowDef maps input field values to priority offsets:
| Field | JSON Key | Type | Description |
|---|---|---|---|
| Key | key | string | Dot-path into run input for value extraction |
| Rules | rules | map[string]int | Value-to-offset mapping |
| DefaultOffset | default_offset | int | Offset when key is empty or the value has no rule |
wf := dag.NewWorkflow("deploy").
WithConcurrency(1, 0).
WithPriority(dag.PriorityConfig{
Key: "environment",
Rules: map[string]int{
"production": 300,
"staging": 100,
"dev": -100,
},
DefaultOffset: 0,
})How Priority Works
Priority is implemented as a time offset on the run’s creation timestamp. Higher offsets make a run appear “older” to the scheduler, causing it to be selected first when a concurrency slot opens.
The engine computes the effective queue position with:
effective_time = created_at - (priority_offset * 1 second)A run with offset 300 appears 5 minutes older than its actual creation time. When the engine selects the oldest pending run to fill an open slot, higher-priority runs win.
Offset Bounds
Priority offsets are clamped to [-600, 600] (plus or minus 10 minutes). This prevents extreme offsets from starving lower-priority runs indefinitely.
Resolution
ResolvePriority computes the offset from the run’s input data:
- If no
PriorityConfigis set, offset is 0 - If
Keyis empty,DefaultOffsetis used - Otherwise, extract the value at
Keyusing dot-path. If the key is missing from the input, the offset is 0, notDefaultOffset - Look the value up in
Rules(compared as a string). If it has no matching rule,DefaultOffsetis used
The resolved offset is stored on WorkflowRun.PriorityOffset when the run is admitted and used by EffectiveTime() for queue ordering.
JSON Schema Example
{
"name": "deploy-pipeline",
"version": "1",
"concurrency": {"max_runs": 1},
"priority": {
"key": "environment",
"rules": {
"production": 300,
"staging": 100
},
"default_offset": 0
},
"steps": [
{
"id": "deploy",
"task": "deploy",
"timeout": "10m",
"type": "normal"
}
]
}With max_runs: 1, only one deploy runs at a time. If a production deploy and a staging deploy are both pending, the production deploy (offset 300) is selected first.
NATS Consumer Priority
Priority applies only to choosing which pending run starts when a concurrency slot opens. It does not reorder tasks on TASK_QUEUES, which workers pull in stream order, and it has no effect on a workflow without max_runs, since no run waits there. The pending scan reads a bounded number of run snapshots, so a very large backlog is not fully ordered.
Related Pages
- Concurrency Limits – the limits that create backlogs
- Rate Limiting – throttling dispatch frequency
- CLI and API – starting runs with input that drives priority