Skip to content

Commit 4e3cb5c

Browse files
Add task management and durable tasks documentation
Syncs documentation for cloudflare/agents PR #683 which adds: - @task() decorator for tracked background operations - Task management API (get, list, cancel, delete) - Durable tasks with Cloudflare Workflows integration - Real-time task updates via WebSocket Related to: cloudflare/agents#683
1 parent e48bbb5 commit 4e3cb5c

File tree

2 files changed

+349
-0
lines changed

2 files changed

+349
-0
lines changed
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
---
2+
title: Durable Tasks
3+
pcx_content_type: concept
4+
sidebar:
5+
order: 7
6+
7+
---
8+
9+
import { MetaInfo, Render, Type, TypeScriptExample, WranglerConfig } from "~/components";
10+
11+
Durable tasks are long-running operations backed by [Cloudflare Workflows](/workflows/). They survive agent restarts and automatically retry on failure. Use durable tasks when operations need to run for extended periods or require guaranteed completion.
12+
13+
## Setup
14+
15+
1. Export `DurableTaskWorkflow` from your worker:
16+
17+
<TypeScriptExample>
18+
19+
```ts
20+
// src/index.ts
21+
import { Agent, routeAgentRequest, DurableTaskWorkflow } from "agents";
22+
23+
export { DurableTaskWorkflow };
24+
25+
export class MyAgent extends Agent<Env> {
26+
// ...
27+
}
28+
```
29+
30+
</TypeScriptExample>
31+
32+
2. Add the workflow binding to `wrangler.jsonc`:
33+
34+
<WranglerConfig>
35+
36+
```jsonc
37+
{
38+
"workflows": [
39+
{
40+
"name": "durable-tasks",
41+
"binding": "DURABLE_TASKS_WORKFLOW",
42+
"class_name": "DurableTaskWorkflow"
43+
}
44+
]
45+
}
46+
```
47+
48+
</WranglerConfig>
49+
50+
## Usage
51+
52+
Mark a task as durable with `durable: true`:
53+
54+
<TypeScriptExample>
55+
56+
```ts
57+
import { Agent, task, type TaskContext } from "agents";
58+
59+
class MyAgent extends Agent<Env> {
60+
@task({ durable: true })
61+
async longAnalysis(input: { repoUrl: string }, ctx: TaskContext) {
62+
ctx.emit("started");
63+
const files = await fetchRepoFiles(input.repoUrl);
64+
ctx.setProgress(50);
65+
const analysis = await analyzeFiles(files);
66+
return analysis;
67+
}
68+
}
69+
```
70+
71+
</TypeScriptExample>
72+
73+
Durable tasks provide:
74+
75+
- **Automatic retries** on failure (configurable)
76+
- **Survives restarts** - the workflow engine manages execution
77+
- **Real-time updates** via `ctx.emit()` and `ctx.setProgress()`
78+
79+
## Retry Configuration
80+
81+
Configure automatic retry behavior for durable tasks:
82+
83+
<TypeScriptExample>
84+
85+
```ts
86+
@task({
87+
durable: true,
88+
retry: {
89+
limit: 3,
90+
delay: "10s",
91+
backoff: "exponential"
92+
}
93+
})
94+
async unreliableTask(input: Input, ctx: TaskContext) {
95+
// Automatically retries on failure
96+
}
97+
```
98+
99+
</TypeScriptExample>
100+
101+
## When to Use Durable Tasks
102+
103+
Use `@task()` (simple) for:
104+
105+
- Operations under 30 seconds
106+
- Tasks that can restart from scratch
107+
108+
Use `@task({ durable: true })` for:
109+
110+
- Long-running operations that need retry guarantees
111+
- Operations that must survive agent restarts
112+
113+
## Custom Workflows
114+
115+
For multi-step workflows with individual checkpoints, extend `AgentWorkflow`:
116+
117+
<TypeScriptExample>
118+
119+
```ts
120+
import { AgentWorkflow, type WorkflowTaskContext } from "agents";
121+
122+
export class AnalysisWorkflow extends AgentWorkflow<Env, { repoUrl: string }> {
123+
async run(ctx: WorkflowTaskContext<{ repoUrl: string }>) {
124+
// Each step is checkpointed - survives restarts
125+
const files = await ctx.step("fetch", async () => {
126+
ctx.emit("phase", { name: "fetching" });
127+
return fetchRepoFiles(ctx.params.repoUrl);
128+
});
129+
130+
// Durable sleep - can wait for hours or days
131+
await ctx.sleep("rate-limit", "1h");
132+
133+
return await ctx.step("analyze", async () => {
134+
ctx.setProgress(50);
135+
return analyzeFiles(files);
136+
});
137+
}
138+
}
139+
```
140+
141+
</TypeScriptExample>
142+
143+
Add to `wrangler.jsonc`:
144+
145+
<WranglerConfig>
146+
147+
```jsonc
148+
{
149+
"workflows": [
150+
{
151+
"name": "analysis-workflow",
152+
"binding": "ANALYSIS_WORKFLOW",
153+
"class_name": "AnalysisWorkflow"
154+
}
155+
]
156+
}
157+
```
158+
159+
</WranglerConfig>
160+
161+
Dispatch the workflow via `this.workflow()`:
162+
163+
<TypeScriptExample>
164+
165+
```ts
166+
class MyAgent extends Agent<Env> {
167+
@callable()
168+
async startAnalysis(input: { repoUrl: string }) {
169+
return this.workflow("ANALYSIS_WORKFLOW", input);
170+
}
171+
}
172+
```
173+
174+
</TypeScriptExample>
175+
176+
### WorkflowTaskContext Methods
177+
178+
Custom workflows have access to:
179+
180+
- `ctx.step(name, fn)` - Checkpointed step, replayed on restart
181+
- `ctx.sleep(name, duration)` - Durable sleep (for example, `"1h"`, `"7d"`)
182+
- `ctx.emit(type, data)` - Send events to clients
183+
- `ctx.setProgress(n)` - Set progress percentage
184+
185+
## Example
186+
187+
Refer to the [task-runner example](https://github.com/cloudflare/agents/tree/main/examples/task-runner) for a complete implementation with both simple and durable tasks.
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
---
2+
title: Task management
3+
pcx_content_type: concept
4+
sidebar:
5+
order: 6
6+
7+
---
8+
9+
import { MetaInfo, Render, Type, TypeScriptExample, WranglerConfig } from "~/components";
10+
11+
Tasks are tracked background operations with progress updates, cancellation support, and real-time synchronization to connected clients. Use the `@task()` decorator to mark methods as tracked tasks that provide visibility into long-running operations.
12+
13+
## Quick Start
14+
15+
Use the `@task()` decorator to mark a method as a tracked task:
16+
17+
<TypeScriptExample>
18+
19+
```ts
20+
import { Agent, task, type TaskContext } from "agents";
21+
22+
class MyAgent extends Agent<Env> {
23+
@task({ timeout: "5m" })
24+
async processData(input: { url: string }, ctx: TaskContext) {
25+
ctx.emit("started", { url: input.url });
26+
ctx.setProgress(25);
27+
28+
const data = await fetch(input.url);
29+
ctx.setProgress(75);
30+
31+
return { processed: true };
32+
}
33+
}
34+
```
35+
36+
</TypeScriptExample>
37+
38+
The client receives real-time updates automatically via WebSocket.
39+
40+
## TaskContext
41+
42+
Every task method receives a `TaskContext` as the second parameter with:
43+
44+
- `emit(type, data)` - Send custom events to connected clients
45+
- `setProgress(n)` - Set progress percentage (0-100)
46+
- `signal` - [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) for cancellation detection
47+
48+
<TypeScriptExample>
49+
50+
```ts
51+
@task({ timeout: "2m" })
52+
async analyze(input: Input, ctx: TaskContext) {
53+
ctx.emit("phase", { name: "fetching" });
54+
55+
if (ctx.signal.aborted) {
56+
throw new Error("Cancelled");
57+
}
58+
59+
ctx.setProgress(50);
60+
// ...
61+
}
62+
```
63+
64+
</TypeScriptExample>
65+
66+
## Managing Tasks
67+
68+
Access tasks via `this.tasks` within your Agent methods:
69+
70+
<TypeScriptExample>
71+
72+
```ts
73+
// Get a specific task
74+
const task = this.tasks.get(taskId);
75+
76+
// List all tasks
77+
const all = this.tasks.list();
78+
79+
// List tasks by status
80+
const running = this.tasks.list({ status: "running" });
81+
82+
// Cancel a task
83+
await this.tasks.cancel(taskId, "User requested");
84+
85+
// Delete a completed task
86+
this.tasks.delete(taskId);
87+
```
88+
89+
</TypeScriptExample>
90+
91+
## Client Updates
92+
93+
Tasks broadcast updates to all connected WebSocket clients via the `CF_AGENT_TASK_UPDATE` message type:
94+
95+
<TypeScriptExample>
96+
97+
```ts
98+
// React client
99+
const agent = useAgent({ agent: "my-agent", name: "default" });
100+
101+
agent.addEventListener("message", (event) => {
102+
const data = JSON.parse(event.data);
103+
if (data.type === "CF_AGENT_TASK_UPDATE") {
104+
const { taskId, task } = data;
105+
// Access: task.status, task.progress, task.events, task.result
106+
}
107+
});
108+
```
109+
110+
</TypeScriptExample>
111+
112+
## Task Options
113+
114+
Configure task behavior with decorator options:
115+
116+
<TypeScriptExample>
117+
118+
```ts
119+
@task({
120+
timeout: "5m", // Cancel if exceeds duration
121+
})
122+
async myTask(input: Input, ctx: TaskContext) {
123+
// ...
124+
}
125+
```
126+
127+
</TypeScriptExample>
128+
129+
Timeout accepts duration strings (`"30s"`, `"5m"`, `"1h"`) or milliseconds as a number.
130+
131+
## Task Status
132+
133+
Tasks transition through these states:
134+
135+
- `pending` - Created, waiting to run
136+
- `running` - Currently executing
137+
- `completed` - Finished successfully
138+
- `failed` - Threw an error
139+
- `aborted` - Cancelled or timed out
140+
141+
## Durable Tasks
142+
143+
For long-running operations that need to survive agent restarts, use durable tasks backed by [Cloudflare Workflows](/workflows/):
144+
145+
<TypeScriptExample>
146+
147+
```ts
148+
@task({ durable: true })
149+
async longProcess(input: Input, ctx: TaskContext) {
150+
// Durable step - survives restarts
151+
const data = await ctx.step("fetch", () => fetchData(input));
152+
153+
// Durable sleep - can sleep for days
154+
await ctx.sleep("rate-limit", "1h");
155+
156+
return await ctx.step("process", () => process(data));
157+
}
158+
```
159+
160+
</TypeScriptExample>
161+
162+
Refer to [Durable Tasks](/agents/api-reference/durable-tasks/) for setup and details.

0 commit comments

Comments
 (0)