Skip to content

Commit 256cdad

Browse files
jsundaiclaude
andcommitted
Refactor Priority & Fairness walkthrough into tabbed demo
- Replace inline MDX with a tabbed PriorityFairnessWalkthrough component (Overview, Try It, How It Works, SDK Examples) - Move Interactive Demos sidebar section after glossary; restore activity-retry-simulator to standalone position in Develop - Remove unicode symbols from simulator buttons Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d463294 commit 256cdad

9 files changed

Lines changed: 763 additions & 235 deletions

File tree

Lines changed: 6 additions & 226 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
---
22
id: priority-fairness-walkthrough
3-
title: Task Queue Priority and Fairness Interactive Demo
4-
sidebar_label: Priority and Fairness (Interactive)
5-
description: Interactively explore how Task Queue Priority and Fairness control dispatch order. Load a preset scenario, step through dispatches, and see exactly which task gets picked next and why.
6-
toc_max_heading_level: 3
3+
title: Task Queue Priority and Fairness - Interactive Walkthrough
4+
sidebar_label: Priority and Fairness
5+
description: Interactively explore how Task Queue Priority and Fairness control dispatch order. Step through scenarios, see which task gets picked next and why, then grab the SDK code.
6+
toc_max_heading_level: 2
77
keywords:
88
- task queue priority
99
- task queue fairness
@@ -15,226 +15,6 @@ tags:
1515
- Priority and Fairness
1616
---
1717

18-
import { PriorityFairnessSimulator } from '@site/src/components';
19-
import SdkTabs from '@site/src/components';
18+
import { PriorityFairnessWalkthrough } from '@site/src/components';
2019

21-
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.
22-
23-
<div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:'1rem', margin:'1.75rem 0 1.25rem', flexWrap:'wrap'}}>
24-
25-
<div style={{border:'1px solid transparent', backgroundImage:'linear-gradient(var(--ifm-background-color, #13111b), var(--ifm-background-color, #13111b)), linear-gradient(255deg, #444ce7 0%, #b664ff 100%)', backgroundOrigin:'padding-box, border-box', backgroundClip:'padding-box, border-box', borderRadius:'0', padding:'1.25rem 1.25rem 1.25rem 1rem'}}>
26-
<div style={{display:'flex', alignItems:'flex-start', gap:'0.875rem', marginBottom:'0.75rem'}}>
27-
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style={{flexShrink:0, marginTop:'1px'}}>
28-
<path d="M3 3h18v3.5H3V3zm0 7.25h13v3.5H3v-3.5zm0 7.25h8v3.5H3v-3.5z" fill="url(#prio-grad)"/>
29-
<defs><linearGradient id="prio-grad" x1="21" y1="3" x2="3" y2="21" gradientUnits="userSpaceOnUse"><stop stopColor="#1FF1A5"/><stop offset="1" stopColor="#C3FF62"/></linearGradient></defs>
30-
</svg>
31-
<strong style={{fontSize:'1.1rem', fontWeight:300, letterSpacing:'0.01em'}}>Priority</strong>
32-
</div>
33-
34-
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.
35-
36-
</div>
37-
38-
<div style={{border:'1px solid transparent', backgroundImage:'linear-gradient(var(--ifm-background-color, #13111b), var(--ifm-background-color, #13111b)), linear-gradient(255deg, #444ce7 0%, #b664ff 100%)', backgroundOrigin:'padding-box, border-box', backgroundClip:'padding-box, border-box', borderRadius:'0', padding:'1.25rem 1.25rem 1.25rem 1rem'}}>
39-
<div style={{display:'flex', alignItems:'flex-start', gap:'0.875rem', marginBottom:'0.75rem'}}>
40-
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style={{flexShrink:0, marginTop:'1px'}}>
41-
<path d="M11 2h2v3.5h-2V2zm0 16.5h2V22h-2v-3.5zM4 7.5h7v9H4v-9zm9 0h7v9h-7v-9zm-2 1.5H4.5V8H11v1zM13 8h6.5v1H13V8z" fill="url(#fair-grad)"/>
42-
<defs><linearGradient id="fair-grad" x1="21" y1="2" x2="3" y2="22" gradientUnits="userSpaceOnUse"><stop stopColor="#1FF1A5"/><stop offset="1" stopColor="#C3FF62"/></linearGradient></defs>
43-
</svg>
44-
<strong style={{fontSize:'1.1rem', fontWeight:300, letterSpacing:'0.01em'}}>Fairness</strong>
45-
</div>
46-
47-
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.
48-
49-
</div>
50-
51-
</div>
52-
53-
Use both together when you need SLA ordering across workload types and fair distribution across tenants within each tier.
54-
55-
<div style={{display:'flex', gap:'6px', margin:'1.25rem 0 2rem', flexWrap:'wrap'}}>
56-
{[['P1','Critical','#ef4444','#fff'],['P2','High','#f97316','#fff'],['P3','Normal (default)','#3b82f6','#fff'],['P4','Low','#22c55e','#000'],['P5','Batch','#94a3b8','#fff']].map(([p,l,bg,fg]) => (
57-
<div key={p} style={{background:bg, color:fg, borderRadius:'0', padding:'5px 14px', fontSize:'12px', fontWeight:600, fontFamily:'var(--ifm-font-family-monospace)', whiteSpace:'nowrap'}}>
58-
{p} · {l}
59-
</div>
60-
))}
61-
</div>
62-
63-
## Try it
64-
65-
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.
66-
67-
<PriorityFairnessSimulator />
68-
69-
---
70-
71-
## How it works
72-
73-
When a Worker polls for the next task, Temporal applies two rules in sequence:
74-
75-
1. **Priority first** - the task with the lowest `priorityKey` wins. If there are tasks at priority `1`, none of the `2`s will dispatch until all `1`s are gone.
76-
2. **Fairness within a tier** - when multiple tasks share the same priority level but carry different `fairnessKey` values, 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.
77-
78-
If no `fairnessKey` is set, tasks within a priority level dispatch in FIFO order.
79-
80-
### When to use Priority vs Fairness
81-
82-
| Scenario | Use |
83-
|---|---|
84-
| Payments should never wait behind inventory syncs | **Priority** |
85-
| Premium users shouldn't be blocked by a single large tenant | **Fairness** |
86-
| SLAs differ across customer tiers and tenants vary in volume | **Both** |
87-
88-
---
89-
90-
## Setup
91-
92-
Priority and Fairness are enabled automatically - no configuration required. Just set `priorityKey`, `fairnessKey`, or both when starting Workflows or Activities.
93-
94-
For self-hosted Temporal, set `matching.useNewMatcher` to `true` in dynamic config. To enable Fairness, also set `matching.enableFairness: true`.
95-
96-
---
97-
98-
## SDK examples
99-
100-
### Workflow - Priority only
101-
102-
<SdkTabs>
103-
<SdkTabs.Go>
104-
```go
105-
workflowOptions := client.StartWorkflowOptions{
106-
ID: "my-workflow-id",
107-
TaskQueue: "my-task-queue",
108-
Priority: temporal.Priority{PriorityKey: 1},
109-
}
110-
we, err := c.ExecuteWorkflow(ctx, workflowOptions, MyWorkflow)
111-
```
112-
</SdkTabs.Go>
113-
<SdkTabs.Java>
114-
```java
115-
WorkflowOptions options = WorkflowOptions.newBuilder()
116-
.setTaskQueue("my-task-queue")
117-
.setPriority(Priority.newBuilder().setPriorityKey(1).build())
118-
.build();
119-
MyWorkflow workflow = client.newWorkflowStub(MyWorkflow.class, options);
120-
workflow.run();
121-
```
122-
</SdkTabs.Java>
123-
<SdkTabs.Python>
124-
```python
125-
await client.start_workflow(
126-
MyWorkflow.run,
127-
id="my-workflow-id",
128-
task_queue="my-task-queue",
129-
priority=Priority(priority_key=1),
130-
)
131-
```
132-
</SdkTabs.Python>
133-
<SdkTabs.TypeScript>
134-
```ts
135-
const handle = await client.workflow.start(MyWorkflow, {
136-
workflowId: "my-workflow-id",
137-
taskQueue: "my-task-queue",
138-
priority: { priorityKey: 1 },
139-
});
140-
```
141-
</SdkTabs.TypeScript>
142-
<SdkTabs.DotNet>
143-
```csharp
144-
var handle = await Client.StartWorkflowAsync(
145-
(MyWorkflow wf) => wf.RunAsync(),
146-
new StartWorkflowOptions("my-workflow-id", "my-task-queue")
147-
{
148-
Priority = new Priority(priorityKey: 1),
149-
}
150-
);
151-
```
152-
</SdkTabs.DotNet>
153-
</SdkTabs>
154-
155-
### Workflow - Priority + Fairness
156-
157-
<SdkTabs>
158-
<SdkTabs.Go>
159-
```go
160-
workflowOptions := client.StartWorkflowOptions{
161-
ID: "my-workflow-id",
162-
TaskQueue: "my-task-queue",
163-
Priority: temporal.Priority{
164-
PriorityKey: 1,
165-
FairnessKey: "tenant-acme",
166-
FairnessWeight: 3.0,
167-
},
168-
}
169-
we, err := c.ExecuteWorkflow(ctx, workflowOptions, MyWorkflow)
170-
```
171-
</SdkTabs.Go>
172-
<SdkTabs.Java>
173-
```java
174-
WorkflowOptions options = WorkflowOptions.newBuilder()
175-
.setTaskQueue("my-task-queue")
176-
.setPriority(Priority.newBuilder()
177-
.setPriorityKey(1)
178-
.setFairnessKey("tenant-acme")
179-
.setFairnessWeight(3.0)
180-
.build())
181-
.build();
182-
MyWorkflow workflow = client.newWorkflowStub(MyWorkflow.class, options);
183-
workflow.run();
184-
```
185-
</SdkTabs.Java>
186-
<SdkTabs.Python>
187-
```python
188-
await client.start_workflow(
189-
MyWorkflow.run,
190-
id="my-workflow-id",
191-
task_queue="my-task-queue",
192-
priority=Priority(priority_key=1, fairness_key="tenant-acme", fairness_weight=3.0),
193-
)
194-
```
195-
</SdkTabs.Python>
196-
<SdkTabs.TypeScript>
197-
```ts
198-
const handle = await client.workflow.start(MyWorkflow, {
199-
workflowId: "my-workflow-id",
200-
taskQueue: "my-task-queue",
201-
priority: { priorityKey: 1, fairnessKey: "tenant-acme", fairnessWeight: 3.0 },
202-
});
203-
```
204-
</SdkTabs.TypeScript>
205-
<SdkTabs.DotNet>
206-
```csharp
207-
var handle = await Client.StartWorkflowAsync(
208-
(MyWorkflow wf) => wf.RunAsync(),
209-
new StartWorkflowOptions("my-workflow-id", "my-task-queue")
210-
{
211-
Priority = new Priority(
212-
priorityKey: 1,
213-
fairnessKey: "tenant-acme",
214-
fairnessWeight: 3.0
215-
),
216-
}
217-
);
218-
```
219-
</SdkTabs.DotNet>
220-
</SdkTabs>
221-
222-
### Temporal CLI
223-
224-
```bash
225-
temporal workflow start \
226-
--type MyWorkflow \
227-
--task-queue my-task-queue \
228-
--workflow-id my-workflow-id \
229-
--priority-key 1 \
230-
--fairness-key tenant-acme \
231-
--fairness-weight 3.0
232-
```
233-
234-
---
235-
236-
## Next steps
237-
238-
- [Task Queue Priority and Fairness - full reference](/develop/task-queue-priority-fairness)
239-
- [Task Queue overview](/task-queue)
240-
- [Worker performance tuning](/develop/worker-performance)
20+
<PriorityFairnessWalkthrough />

sidebars.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -333,15 +333,7 @@ module.exports = {
333333
],
334334
},
335335
'develop/environment-configuration',
336-
{
337-
type: 'category',
338-
label: 'Interactive Demos',
339-
collapsed: false,
340-
items: [
341-
'develop/activity-retry-simulator',
342-
'develop/priority-fairness-walkthrough',
343-
],
344-
},
336+
'develop/activity-retry-simulator',
345337
'develop/worker-performance',
346338
'develop/worker-tuning-reference',
347339
'develop/safe-deployments',
@@ -898,6 +890,15 @@ module.exports = {
898890
],
899891
},
900892
'glossary',
893+
{
894+
type: 'category',
895+
label: 'Interactive Demos',
896+
collapsed: false,
897+
items: [
898+
'develop/activity-retry-simulator',
899+
'develop/priority-fairness-walkthrough',
900+
],
901+
},
901902
'with-ai',
902903
// {
903904
// type: "autogenerated",
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import React from 'react';
2+
import styles from './walkthrough.module.css';
3+
4+
const STEPS = [
5+
{
6+
title: 'Worker polls the Task Queue',
7+
body: 'When a Worker is ready, it sends a poll request to the Task Queue. Temporal evaluates all waiting tasks and applies Priority and Fairness rules to decide which one to return.',
8+
},
9+
{
10+
title: 'Priority tier is selected first',
11+
body: 'Temporal finds the lowest priorityKey among all waiting tasks. Every task at priority 1 will be dispatched before any task at priority 2 moves, and so on. Tasks at the same level compete under Fairness rules.',
12+
},
13+
{
14+
title: 'Fairness distributes capacity within the tier',
15+
body: 'Within a priority tier, Temporal tracks how many tasks each fairnessKey has received relative to its fairnessWeight. The key that is furthest behind its expected share gets the next dispatch. This prevents any single tenant from consuming disproportionate capacity, even if they have a deep backlog.',
16+
},
17+
{
18+
title: 'No fairnessKey means strict FIFO within the tier',
19+
body: 'If you set priorityKey but omit fairnessKey, tasks at the same priority level are dispatched in arrival order. Fairness only applies when at least one task in the tier carries a fairnessKey.',
20+
},
21+
{
22+
title: 'Priority and Fairness are per Task Queue',
23+
body: 'The rules apply independently per Task Queue. Workers on the same Task Queue share the same dispatch ordering. Workers on separate Task Queues are unaffected by each other.',
24+
},
25+
];
26+
27+
const WHEN_ROWS = [
28+
{ scenario: 'Payments should never wait behind inventory syncs', use: 'Priority', badge: 'badgePriority' },
29+
{ scenario: 'Premium users should not be blocked by a large free-tier tenant', use: 'Fairness', badge: 'badgeFairness' },
30+
{ scenario: 'SLAs differ across customer tiers and tenants vary in volume', use: 'Both', badge: 'badgeBoth' },
31+
];
32+
33+
export default function HowItWorks({ onNext }) {
34+
return (
35+
<div className={styles.section}>
36+
<p className={styles.lead}>
37+
When a Worker polls for the next task, Temporal applies two rules in sequence: Priority
38+
determines which tier goes first, and Fairness distributes capacity among tenants within
39+
each tier.
40+
</p>
41+
42+
<div className={styles.stepList}>
43+
{STEPS.map((step, i) => (
44+
<div key={i} className={styles.step}>
45+
<div className={styles.stepNum}>{i + 1}</div>
46+
<div className={styles.stepContent}>
47+
<p className={styles.stepTitle}>{step.title}</p>
48+
<p className={styles.stepBody}>{step.body}</p>
49+
</div>
50+
</div>
51+
))}
52+
</div>
53+
54+
<h3 className={styles.sectionHeading}>When to use Priority vs Fairness</h3>
55+
<table className={styles.whenTable}>
56+
<thead>
57+
<tr>
58+
<th>Scenario</th>
59+
<th>Use</th>
60+
</tr>
61+
</thead>
62+
<tbody>
63+
{WHEN_ROWS.map((row, i) => (
64+
<tr key={i}>
65+
<td>{row.scenario}</td>
66+
<td>
67+
<span className={`${styles.badge} ${styles[row.badge]}`}>{row.use}</span>
68+
</td>
69+
</tr>
70+
))}
71+
</tbody>
72+
</table>
73+
74+
<button className={styles.nextBtn} onClick={onNext}>
75+
SDK Examples
76+
</button>
77+
</div>
78+
);
79+
}

0 commit comments

Comments
 (0)