Task Queue Priority and Fairness — Interactive Demo
When multiple workloads compete for Workers, Task Queue Priority determines which tasks get picked first, while Task Queue Fairness ensures no single workload can crowd out the rest.
Every task carries a priorityKey from 1 (critical) to 5 (batch), with 3 as the default. When a Worker polls, it always picks the lowest-numbered task first regardless of arrival time. This lets you share a single Worker pool across very different workloads and guarantee that time-sensitive work never waits behind low-urgency jobs.
Without Fairness, tasks at the same priority dispatch strictly FIFO, so a backlog-heavy tenant can block everyone else at that level indefinitely. Fairness groups tasks by fairnessKey and dispatches proportionally by fairnessWeight. A key with weight 5 gets roughly 5x more dispatches than a key with weight 1, but no key is ever completely locked out.
Use both together when you need SLA ordering across workload types and fair distribution across tenants within each tier.
Try it
Load a preset or build your own queue. Use Step -> to dispatch one task at a time and watch which task gets picked next, or Dispatch All to see the full order at once.
Fairness Keys
Priority onlyNo fairness keys — tasks dispatch in strict priority order (FIFO within same priority).
Add Task
Priority Key Legend
Task Queue
Load a scenario from the dropdown above, or add tasks manually.
How it works
When a Worker polls for the next task, Temporal applies two rules in sequence:
- Priority first - the task with the lowest
priorityKeywins. If there are tasks at priority1, none of the2s will dispatch until all1s are gone. - Fairness within a tier - when multiple tasks share the same priority level but carry different
fairnessKeyvalues, Temporal tracks how many tasks each key has received relative to its weight and dispatches from the key that is furthest behind its expected share.
If no fairnessKey is set, tasks within a priority level dispatch in FIFO order.
When to use Priority vs Fairness
| Scenario | Use |
|---|---|
| Payments should never wait behind inventory syncs | Priority |
| Premium users shouldn't be blocked by a single large tenant | Fairness |
| SLAs differ across customer tiers and tenants vary in volume | Both |
Setup
Priority and Fairness are enabled automatically - no configuration required. Just set priorityKey, fairnessKey, or both when starting Workflows or Activities.
For self-hosted Temporal, set matching.useNewMatcher to true in dynamic config. To enable Fairness, also set matching.enableFairness: true.
SDK examples
Workflow - Priority only
workflowOptions := client.StartWorkflowOptions{
ID: "my-workflow-id",
TaskQueue: "my-task-queue",
Priority: temporal.Priority{PriorityKey: 1},
}
we, err := c.ExecuteWorkflow(ctx, workflowOptions, MyWorkflow)
WorkflowOptions options = WorkflowOptions.newBuilder()
.setTaskQueue("my-task-queue")
.setPriority(Priority.newBuilder().setPriorityKey(1).build())
.build();
MyWorkflow workflow = client.newWorkflowStub(MyWorkflow.class, options);
workflow.run();
await client.start_workflow(
MyWorkflow.run,
id="my-workflow-id",
task_queue="my-task-queue",
priority=Priority(priority_key=1),
)
const handle = await client.workflow.start(MyWorkflow, {
workflowId: "my-workflow-id",
taskQueue: "my-task-queue",
priority: { priorityKey: 1 },
});
var handle = await Client.StartWorkflowAsync(
(MyWorkflow wf) => wf.RunAsync(),
new StartWorkflowOptions("my-workflow-id", "my-task-queue")
{
Priority = new Priority(priorityKey: 1),
}
);
Workflow - Priority + Fairness
workflowOptions := client.StartWorkflowOptions{
ID: "my-workflow-id",
TaskQueue: "my-task-queue",
Priority: temporal.Priority{
PriorityKey: 1,
FairnessKey: "tenant-acme",
FairnessWeight: 3.0,
},
}
we, err := c.ExecuteWorkflow(ctx, workflowOptions, MyWorkflow)
WorkflowOptions options = WorkflowOptions.newBuilder()
.setTaskQueue("my-task-queue")
.setPriority(Priority.newBuilder()
.setPriorityKey(1)
.setFairnessKey("tenant-acme")
.setFairnessWeight(3.0)
.build())
.build();
MyWorkflow workflow = client.newWorkflowStub(MyWorkflow.class, options);
workflow.run();
await client.start_workflow(
MyWorkflow.run,
id="my-workflow-id",
task_queue="my-task-queue",
priority=Priority(priority_key=1, fairness_key="tenant-acme", fairness_weight=3.0),
)
const handle = await client.workflow.start(MyWorkflow, {
workflowId: "my-workflow-id",
taskQueue: "my-task-queue",
priority: { priorityKey: 1, fairnessKey: "tenant-acme", fairnessWeight: 3.0 },
});
var handle = await Client.StartWorkflowAsync(
(MyWorkflow wf) => wf.RunAsync(),
new StartWorkflowOptions("my-workflow-id", "my-task-queue")
{
Priority = new Priority(
priorityKey: 1,
fairnessKey: "tenant-acme",
fairnessWeight: 3.0
),
}
);
Temporal CLI
temporal workflow start \
--type MyWorkflow \
--task-queue my-task-queue \
--workflow-id my-workflow-id \
--priority-key 1 \
--fairness-key tenant-acme \
--fairness-weight 3.0