← Vytvářejte agenty na Cloudflare / agents / runtime / execution
Spouštění Workflows
Integrace Cloudflare Workflows s Agents pro trvalé, vícekrokové zpracování na pozadí, zatímco Agents zajišťují komunikaci v reálném čase.
Rychlý start
1. Definujte Workflow
Rozšiřte AgentWorkflow pro typovaný přístup k původnímu Agentu:
import { AgentWorkflow } from "agents/workflows";
export class ProcessingWorkflow extends AgentWorkflow {
async run(event, step) {
const params = event.payload;
const result = await step.do("process-data", async () => {
return processData(params.data);
});
// Non-durable: progress reporting (may repeat on retry)
await this.reportProgress({
step: "process",
status: "complete",
percent: 0.5,
});
// Broadcast to connected WebSocket clients
this.broadcastToClients({ type: "update", taskId: params.taskId });
await step.do("save-results", async () => {
// Call Agent methods via RPC
await this.agent.saveResult(params.taskId, result);
});
// Durable: idempotent, won't repeat on retry
await step.reportComplete(result);
return result;
}
}import { AgentWorkflow } from "agents/workflows";
import type { AgentWorkflowEvent, AgentWorkflowStep } from "agents/workflows";
import type { MyAgent } from "./agent";
type TaskParams = { taskId: string; data: string };
export class ProcessingWorkflow extends AgentWorkflow<MyAgent, TaskParams> {
async run(event: AgentWorkflowEvent<TaskParams>, step: AgentWorkflowStep) {
const params = event.payload;
const result = await step.do("process-data", async () => {
return processData(params.data);
});
// Non-durable: progress reporting (may repeat on retry)
await this.reportProgress({
step: "process",
status: "complete",
percent: 0.5,
});
// Broadcast to connected WebSocket clients
this.broadcastToClients({ type: "update", taskId: params.taskId });
await step.do("save-results", async () => {
// Call Agent methods via RPC
await this.agent.saveResult(params.taskId, result);
});
// Durable: idempotent, won't repeat on retry
await step.reportComplete(result);
return result;
}
}2. Spusťte Workflow z Agenta
Použijte runWorkflow() ke spuštění a sledování workflows:
import { Agent } from "agents";
export class MyAgent extends Agent {
async startTask(taskId, data) {
const instanceId = await this.runWorkflow("PROCESSING_WORKFLOW", {
taskId,
data,
});
return { instanceId };
}
async onWorkflowProgress(workflowName, instanceId, progress) {
this.broadcast(JSON.stringify({ type: "workflow-progress", progress }));
}
async onWorkflowComplete(workflowName, instanceId, result) {
console.log(`Workflow completed:`, result);
}
async saveResult(taskId, result) {
this
.sql`INSERT INTO results (task_id, data) VALUES (${taskId}, ${JSON.stringify(result)})`;
}
}import { Agent } from "agents";
export class MyAgent extends Agent {
async startTask(taskId: string, data: string) {
const instanceId = await this.runWorkflow("PROCESSING_WORKFLOW", {
taskId,
data,
});
return { instanceId };
}
async onWorkflowProgress(
workflowName: string,
instanceId: string,
progress: unknown,
) {
this.broadcast(JSON.stringify({ type: "workflow-progress", progress }));
}
async onWorkflowComplete(
workflowName: string,
instanceId: string,
result?: unknown,
) {
console.log(`Workflow completed:`, result);
}
async saveResult(taskId: string, result: unknown) {
this
.sql`INSERT INTO results (task_id, data) VALUES (${taskId}, ${JSON.stringify(result)})`;
}
}3. Nakonfigurujte Wrangler
{
"name": "my-app",
"main": "src/index.ts",
// Set this to today's date
"compatibility_date": "2026-08-28",
"durable_objects": {
"bindings": [{ "name": "MY_AGENT", "class_name": "MyAgent" }],
},
"workflows": [
{
"name": "processing-workflow",
"binding": "PROCESSING_WORKFLOW",
"class_name": "ProcessingWorkflow",
},
],
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] }],
}name = "my-app"
main = "src/index.ts"
# Set this to today's date
compatibility_date = "2026-08-28"
[[durable_objects.bindings]]
name = "MY_AGENT"
class_name = "MyAgent"
[[workflows]]
name = "processing-workflow"
binding = "PROCESSING_WORKFLOW"
class_name = "ProcessingWorkflow"
[[migrations]]
tag = "v1"
new_sqlite_classes = [ "MyAgent" ]Třída AgentWorkflow
Základní třída pro Workflows integrující se s Agents.
Typové parametry
| Parametr | Popis |
|---|---|
AgentType |
Typ třídy Agent pro typované RPC |
Params |
Parametry předané workflow |
ProgressType |
Typ pro hlášení průběhu (výchozí hodnota DefaultProgress) |
Env |
Typ prostředí (výchozí Cloudflare.Env) |
Vlastnosti
| Vlastnost | Typ | Popis |
|---|---|---|
agent |
Stub | Typovaný stub pro volání metod Agent. U workflow spuštěných ze sub-agenta jde o stub pouze pro RPC zpět k původnímu facetu; pro HTTP nebo WebSocket použijte směrování sub-agentů fetch() provoz |
instanceId |
string | ID instance workflow |
workflowName |
string | Název bindingu workflow |
env |
Env | Vazby prostředí |
Instanční metody (netrvalé)
Tyto metody se při opakování pokusu mohou provést znovu. Použijte je pro odlehčené, časté aktualizace.
reportProgress(progress)
Nahlaste průběh Agentovi. Spouští onWorkflowProgress callback.
await this.reportProgress({
step: "processing",
status: "running",
percent: 0.5,
});await this.reportProgress({
step: "processing",
status: "running",
percent: 0.5,
});broadcastToClients(message)
Rozešle zprávu všem klientům WebSocket připojeným k Agentovi.
this.broadcastToClients({ type: "update", data: result });this.broadcastToClients({ type: "update", data: result });waitForApproval(step, options?)
Počkejte na událost schválení. Vyvolá WorkflowRejectedError pokud je zamítnuto.
const approval = await this.waitForApproval(step, {
timeout: "7 days",
});const approval = await this.waitForApproval<{ approvedBy: string }>(step, {
timeout: "7 days",
});Metody kroku (trvalé)
Tyto metody jsou idempotentní a při opakování pokusu se neprovedou znovu. Použijte je pro změny stavu, které musí zůstat trvalé.
| Metoda | Popis |
|---|---|
step.reportComplete(result?) |
Nahlásit úspěšné dokončení |
step.reportError(error) |
Nahlaste chybu |
step.sendEvent(event) |
Odeslat vlastní událost Agentu |
step.updateAgentState(state) |
Nahrazení stavu Agentu (vysílání klientům) |
step.mergeAgentState(partial) |
Sloučit do stavu Agenta (odešle klientům) |
step.resetAgentState() |
Resetovat stav Agenta na initialState |
Typ DefaultProgress
type DefaultProgress = {
step?: string;
status?: "pending" | "running" | "complete" | "error";
message?: string;
percent?: number;
[key: string]: unknown;
};Metody pracovního postupu agenta
Metody dostupné na Agent třída pro správu Workflow.
runWorkflow(workflowName, params, options?)
Spusťte instanci workflow a sledujte ji v databázi Agent.
Parametry:
| Parametr | Typ | Popis |
|---|---|---|
workflowName |
string | Název vazby workflow z env |
params |
objekt | Parametry, které se mají předat workflow |
options.id |
string | Vlastní ID workflow (automaticky vygenerované, pokud není zadáno) |
options.metadata |
objekt | Metadata uložená pro dotazování (nejsou předávána do workflow) |
options.agentBinding |
string | Název vazby Agent (automaticky detekováno, pokud není zadáno). Při volání z podřízeného agenta jde o název vazby kořenového Agenta |
Vrací: Promise<string> - ID instance Workflow
const instanceId = await this.runWorkflow(
"MY_WORKFLOW",
{ taskId: "123" },
{
metadata: { userId: "user-456", priority: "high" },
},
);const instanceId = await this.runWorkflow(
"MY_WORKFLOW",
{ taskId: "123" },
{
metadata: { userId: "user-456", priority: "high" },
},
);Spouštění workflows z podřízených agentů
Podřízení agenti mohou volat this.runWorkflow() přímo. Workflow se sleduje v databázi SQLite původního dílčího agenta a this.agent uvnitř AgentWorkflow směruje zpět k témuž podřízenému agentovi pro volání RPC, callbacky, aktualizace stavu a vysílání.
Nadřazení agenti automaticky nevypisují ani neřídí workflows, které spustí sub-agent. SubAgentStub<T> zpřístupňuje pouze uživatelsky definované metody, nikoli zděděné Agent metody, jako jsou approveWorkflow() nebo getWorkflow(). Chcete-li workflow spuštěný potomkem řídit z nadřazeného agenta, definujte na potomkovi malé wrapper metody a volejte je přes stub podřízeného agenta.
export class ParentAgent extends Agent {
async startChildWorkflow(childName, task) {
const child = await this.subAgent(ChildAgent, childName);
return child.startWorkflow(task);
}
async approveChildWorkflow(childName, workflowId) {
const child = await this.subAgent(ChildAgent, childName);
return child.approveChildWorkflow(workflowId);
}
}
export class ChildAgent extends Agent {
async startWorkflow(task) {
return this.runWorkflow("CHILD_WORKFLOW", { task });
}
async approveChildWorkflow(workflowId) {
return this.approveWorkflow(workflowId);
}
async getChildWorkflow(workflowId) {
return this.getWorkflow(workflowId);
}
}export class ParentAgent extends Agent {
async startChildWorkflow(childName: string, task: string) {
const child = await this.subAgent(ChildAgent, childName);
return child.startWorkflow(task);
}
async approveChildWorkflow(childName: string, workflowId: string) {
const child = await this.subAgent(ChildAgent, childName);
return child.approveChildWorkflow(workflowId);
}
}
export class ChildAgent extends Agent {
async startWorkflow(task: string) {
return this.runWorkflow("CHILD_WORKFLOW", { task });
}
async approveChildWorkflow(workflowId: string) {
return this.approveWorkflow(workflowId);
}
async getChildWorkflow(workflowId: string) {
return this.getWorkflow(workflowId);
}
}Pro původ z podřízeného agenta, AgentWorkflow.agent je pahýl pouze pro RPC. Použijte ho k volání metod Agent, ale pro routeSubAgentRequest() nebo /agents/{parent}/{name}/sub/{child}/{name} tvar URL pro externí směrování HTTP nebo WebSocket namísto this.agent.fetch().
Omezení směrování
Protože je původní identita trvale uložena v parametrech workflow a při každém callbacku se znovu přehrává, platí pro všechny workflow (ať už patří podřízeným agentům, nebo agentům nejvyšší úrovně) několik omezení:
- Callbacky vyhledají Agent podle názvu. Runtime znovu vyhledá původní Agent pomocí
getAgentByName(...). Pokud jste Agenta adresovali přímo pomocí ID Durable Object (idFromString/get(id)) místo podle názvu, callbacky skončí na jiné instanci. Workflow spouštějte z Agentů adresovaných podle názvu. - Názvy tříd musí zůstat zachovány i po bundlingu. Výchozí cesta je indexovaná podle
constructor.name. Nakonfigurujte svůj bundler tak, aby zachovával názvy tříd (esbuildkeepNames: true) takže průběh, dokončení athis.agentRPC lze směrovat zpět ke správnému facetu. agentBindingje kořenová vazba. Když předáteoptions.agentBindingze sub-agenta použijte kořen Název vazby Durable Object agenta, nikoli podřízené vazby.
sendWorkflowEvent(workflowName, instanceId, event)
Odešlete událost běžícímu workflow.
await this.sendWorkflowEvent("MY_WORKFLOW", instanceId, {
type: "custom-event",
payload: { action: "proceed" },
});await this.sendWorkflowEvent("MY_WORKFLOW", instanceId, {
type: "custom-event",
payload: { action: "proceed" },
});getWorkflowStatus(workflowName, instanceId)
Získat stav workflow a aktualizovat sledovaný záznam.
const status = await this.getWorkflowStatus("MY_WORKFLOW", instanceId);
// { status: 'running', output: null, error: null }const status = await this.getWorkflowStatus("MY_WORKFLOW", instanceId);
// { status: 'running', output: null, error: null }getWorkflow(instanceId)
Získat sledovaný workflow podle ID.
const workflow = this.getWorkflow(instanceId);
// { instanceId, workflowName, status, metadata, error, createdAt, ... }const workflow = this.getWorkflow(instanceId);
// { instanceId, workflowName, status, metadata, error, createdAt, ... }getWorkflows(criteria?)
Dotazujte se na sledované workflow pomocí stránkování založeného na kurzoru. Vrací WorkflowPage s workflow, celkovým počtem a kurzorem pro další stránku.
// Get running workflows (default limit is 50, max is 100)
const { workflows, total } = this.getWorkflows({ status: "running" });
// Filter by metadata
const { workflows: userWorkflows } = this.getWorkflows({
metadata: { userId: "user-456" },
});
// Pagination with cursor
const page1 = this.getWorkflows({
status: ["complete", "errored"],
limit: 20,
orderBy: "desc",
});
console.log(`Showing ${page1.workflows.length} of ${page1.total} workflows`);
// Get next page using cursor
if (page1.nextCursor) {
const page2 = this.getWorkflows({
status: ["complete", "errored"],
limit: 20,
orderBy: "desc",
cursor: page1.nextCursor,
});
}// Get running workflows (default limit is 50, max is 100)
const { workflows, total } = this.getWorkflows({ status: "running" });
// Filter by metadata
const { workflows: userWorkflows } = this.getWorkflows({
metadata: { userId: "user-456" },
});
// Pagination with cursor
const page1 = this.getWorkflows({
status: ["complete", "errored"],
limit: 20,
orderBy: "desc",
});
console.log(`Showing ${page1.workflows.length} of ${page1.total} workflows`);
// Get next page using cursor
if (page1.nextCursor) {
const page2 = this.getWorkflows({
status: ["complete", "errored"],
limit: 20,
orderBy: "desc",
cursor: page1.nextCursor,
});
} WorkflowPage typ:
type WorkflowPage = {
workflows: WorkflowInfo[];
total: number; // Total matching workflows
nextCursor: string | null; // null when no more pages
};deleteWorkflow(instanceId)
Smaže jeden sledovací záznam instance workflow. Vrací true pokud je smazáno, false pokud nebylo nalezeno.
deleteWorkflows(criteria?)
Smaže sledovací záznamy instancí workflow odpovídající zadaným kritériím.
// Delete completed workflow instances older than 7 days
this.deleteWorkflows({
status: "complete",
createdBefore: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
});
// Delete all errored and terminated workflows
this.deleteWorkflows({
status: ["errored", "terminated"],
});// Delete completed workflow instances older than 7 days
this.deleteWorkflows({
status: "complete",
createdBefore: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
});
// Delete all errored and terminated workflows
this.deleteWorkflows({
status: ["errored", "terminated"],
});terminateWorkflow(instanceId)
Okamžitě ukončí běžící workflow. Nastaví stav na "terminated".
await this.terminateWorkflow(instanceId);await this.terminateWorkflow(instanceId);pauseWorkflow(instanceId)
Pozastavte běžící workflow. Workflow lze později obnovit pomocí resumeWorkflow().
await this.pauseWorkflow(instanceId);await this.pauseWorkflow(instanceId);resumeWorkflow(instanceId)
Obnoví pozastavený workflow.
await this.resumeWorkflow(instanceId);await this.resumeWorkflow(instanceId);restartWorkflow(instanceId, options?)
Restartuje instanci workflow od začátku se stejným ID.
// Reset tracking (default) - clears timestamps and error fields
await this.restartWorkflow(instanceId);
// Preserve original timestamps
await this.restartWorkflow(instanceId, { resetTracking: false });// Reset tracking (default) - clears timestamps and error fields
await this.restartWorkflow(instanceId);
// Preserve original timestamps
await this.restartWorkflow(instanceId, { resetTracking: false });approveWorkflow(instanceId, options?)
Schválí čekající workflow. Použijte s waitForApproval() ve workflow.
await this.approveWorkflow(instanceId, {
reason: "Approved by admin",
metadata: { approvedBy: userId },
});await this.approveWorkflow(instanceId, {
reason: "Approved by admin",
metadata: { approvedBy: userId },
});rejectWorkflow(instanceId, options?)
Odmítněte čekající workflow. Způsobí to waitForApproval() vyhodit WorkflowRejectedError.
await this.rejectWorkflow(instanceId, { reason: "Request denied" });await this.rejectWorkflow(instanceId, { reason: "Request denied" });migrateWorkflowBinding(oldName, newName)
Migrovat sledované workflow po přejmenování vazby workflow.
class MyAgent extends Agent {
async onStart() {
this.migrateWorkflowBinding("OLD_WORKFLOW", "NEW_WORKFLOW");
}
}class MyAgent extends Agent {
async onStart() {
this.migrateWorkflowBinding("OLD_WORKFLOW", "NEW_WORKFLOW");
}
}Callbacky životního cyklu
Přepište tyto metody ve svém Agentovi, abyste zpracovali události workflow:
| Callback | Parametry | Popis |
|---|---|---|
onWorkflowProgress |
workflowName, instanceId, progress |
Volá se, když workflow nahlásí průběh |
onWorkflowComplete |
workflowName, instanceId, result? |
Volá se při dokončení workflow |
onWorkflowError |
workflowName, instanceId, error |
Volá se, když ve workflow dojde k chybě |
onWorkflowEvent |
workflowName, instanceId, event |
Volá se, když workflow odešle událost |
onWorkflowCallback |
callback: WorkflowCallback |
Volá se pro všechny typy callbacků |
class MyAgent extends Agent {
async onWorkflowProgress(workflowName, instanceId, progress) {
this.broadcast(
JSON.stringify({ type: "progress", workflowName, instanceId, progress }),
);
}
async onWorkflowComplete(workflowName, instanceId, result) {
console.log(`${workflowName}/${instanceId} completed`);
}
async onWorkflowError(workflowName, instanceId, error) {
console.error(`${workflowName}/${instanceId} failed:`, error);
}
}class MyAgent extends Agent {
async onWorkflowProgress(
workflowName: string,
instanceId: string,
progress: unknown,
) {
this.broadcast(
JSON.stringify({ type: "progress", workflowName, instanceId, progress }),
);
}
async onWorkflowComplete(
workflowName: string,
instanceId: string,
result?: unknown,
) {
console.log(`${workflowName}/${instanceId} completed`);
}
async onWorkflowError(
workflowName: string,
instanceId: string,
error: string,
) {
console.error(`${workflowName}/${instanceId} failed:`, error);
}
}Sledování workflow
Workflows spuštěné pomocí runWorkflow() se automaticky sledují ve vnitřní databázi Agenta, který je vytvořil. Workflows můžete dotazovat, filtrovat a spravovat pomocí metod popsaných výše (getWorkflow(), getWorkflows(), deleteWorkflow(), atd.).
Hodnoty stavu
| Stav | Popis |
|---|---|
queued |
Čekání na spuštění |
running |
Právě se provádí |
paused |
Pozastaveno uživatelem |
waiting |
Čekání na událost |
complete |
Dokončeno úspěšně |
errored |
Selhalo s chybou |
terminated |
Ručně ukončeno |
Použijte metadata možnost v runWorkflow() k uložení dotazovatelných informací (například ID uživatelů nebo typy úloh), podle kterých můžete později filtrovat pomocí getWorkflows().
Příklady
Schválení s lidským zásahem
import { AgentWorkflow } from "agents/workflows";
export class ApprovalWorkflow extends AgentWorkflow {
async run(event, step) {
const request = await step.do("prepare", async () => {
return { ...event.payload, preparedAt: Date.now() };
});
await this.reportProgress({
step: "approval",
status: "pending",
message: "Awaiting approval",
});
// Throws WorkflowRejectedError if rejected
const approval = await this.waitForApproval(step, {
timeout: "7 days",
});
console.log("Approved by:", approval?.approvedBy);
const result = await step.do("execute", async () => {
return executeRequest(request);
});
await step.reportComplete(result);
return result;
}
}
class MyAgent extends Agent {
async handleApproval(instanceId, userId) {
await this.approveWorkflow(instanceId, {
reason: "Approved by admin",
metadata: { approvedBy: userId },
});
}
async handleRejection(instanceId, reason) {
await this.rejectWorkflow(instanceId, { reason });
}
}import { AgentWorkflow } from "agents/workflows";
import type { AgentWorkflowEvent, AgentWorkflowStep } from "agents/workflows";
export class ApprovalWorkflow extends AgentWorkflow<MyAgent, RequestParams> {
async run(event: AgentWorkflowEvent<RequestParams>, step: AgentWorkflowStep) {
const request = await step.do("prepare", async () => {
return { ...event.payload, preparedAt: Date.now() };
});
await this.reportProgress({
step: "approval",
status: "pending",
message: "Awaiting approval",
});
// Throws WorkflowRejectedError if rejected
const approval = await this.waitForApproval<{ approvedBy: string }>(step, {
timeout: "7 days",
});
console.log("Approved by:", approval?.approvedBy);
const result = await step.do("execute", async () => {
return executeRequest(request);
});
await step.reportComplete(result);
return result;
}
}
class MyAgent extends Agent {
async handleApproval(instanceId: string, userId: string) {
await this.approveWorkflow(instanceId, {
reason: "Approved by admin",
metadata: { approvedBy: userId },
});
}
async handleRejection(instanceId: string, reason: string) {
await this.rejectWorkflow(instanceId, { reason });
}
}Opakování s odkladem
import { AgentWorkflow } from "agents/workflows";
export class ResilientWorkflow extends AgentWorkflow {
async run(event, step) {
const result = await step.do(
"call-api",
{
retries: { limit: 5, delay: "10 seconds", backoff: "exponential" },
timeout: "5 minutes",
},
async () => {
const response = await fetch("https://api.example.com/process", {
method: "POST",
body: JSON.stringify(event.payload),
});
if (!response.ok) throw new Error(`API error: ${response.status}`);
return response.json();
},
);
await step.reportComplete(result);
return result;
}
}import { AgentWorkflow } from "agents/workflows";
import type { AgentWorkflowEvent, AgentWorkflowStep } from "agents/workflows";
export class ResilientWorkflow extends AgentWorkflow<MyAgent, TaskParams> {
async run(event: AgentWorkflowEvent<TaskParams>, step: AgentWorkflowStep) {
const result = await step.do(
"call-api",
{
retries: { limit: 5, delay: "10 seconds", backoff: "exponential" },
timeout: "5 minutes",
},
async () => {
const response = await fetch("https://api.example.com/process", {
method: "POST",
body: JSON.stringify(event.payload),
});
if (!response.ok) throw new Error(`API error: ${response.status}`);
return response.json();
},
);
await step.reportComplete(result);
return result;
}
}Synchronizace stavu
Workflows mohou trvale aktualizovat stav Agent přes step, který automaticky vysílá všem připojeným klientům:
import { AgentWorkflow } from "agents/workflows";
export class StatefulWorkflow extends AgentWorkflow {
async run(event, step) {
// Replace entire state (durable, broadcasts to clients)
await step.updateAgentState({
currentTask: {
id: event.payload.taskId,
status: "processing",
startedAt: Date.now(),
},
});
const result = await step.do("process", async () =>
processTask(event.payload),
);
// Merge partial state (durable, keeps existing fields)
await step.mergeAgentState({
currentTask: { status: "complete", result, completedAt: Date.now() },
});
await step.reportComplete(result);
return result;
}
}import { AgentWorkflow } from "agents/workflows";
import type { AgentWorkflowEvent, AgentWorkflowStep } from "agents/workflows";
export class StatefulWorkflow extends AgentWorkflow<MyAgent, TaskParams> {
async run(event: AgentWorkflowEvent<TaskParams>, step: AgentWorkflowStep) {
// Replace entire state (durable, broadcasts to clients)
await step.updateAgentState({
currentTask: {
id: event.payload.taskId,
status: "processing",
startedAt: Date.now(),
},
});
const result = await step.do("process", async () =>
processTask(event.payload),
);
// Merge partial state (durable, keeps existing fields)
await step.mergeAgentState({
currentTask: { status: "complete", result, completedAt: Date.now() },
});
await step.reportComplete(result);
return result;
}
}Vlastní typy průběhu
Definujte vlastní typy průběhu pro reportování specifické pro danou doménu:
import { AgentWorkflow } from "agents/workflows";
// Custom progress type for data pipeline
// Workflow with custom progress type (3rd type parameter)
export class ETLWorkflow extends AgentWorkflow {
async run(event, step) {
await this.reportProgress({
stage: "extract",
recordsProcessed: 0,
totalRecords: 1000,
currentTable: "users",
});
// ... processing
}
}
// Agent receives typed progress
class MyAgent extends Agent {
async onWorkflowProgress(workflowName, instanceId, progress) {
const p = progress;
console.log(`Stage: ${p.stage}, ${p.recordsProcessed}/${p.totalRecords}`);
}
}import { AgentWorkflow } from "agents/workflows";
import type { AgentWorkflowEvent, AgentWorkflowStep } from "agents/workflows";
// Custom progress type for data pipeline
type PipelineProgress = {
stage: "extract" | "transform" | "load";
recordsProcessed: number;
totalRecords: number;
currentTable?: string;
};
// Workflow with custom progress type (3rd type parameter)
export class ETLWorkflow extends AgentWorkflow<
MyAgent,
ETLParams,
PipelineProgress
> {
async run(event: AgentWorkflowEvent<ETLParams>, step: AgentWorkflowStep) {
await this.reportProgress({
stage: "extract",
recordsProcessed: 0,
totalRecords: 1000,
currentTable: "users",
});
// ... processing
}
}
// Agent receives typed progress
class MyAgent extends Agent {
async onWorkflowProgress(
workflowName: string,
instanceId: string,
progress: unknown,
) {
const p = progress as PipelineProgress;
console.log(`Stage: ${p.stage}, ${p.recordsProcessed}/${p.totalRecords}`);
}
}Strategie vyčištění
Interní cf_agents_workflows tabulka může neomezeně růst, proto implementujte zásadu uchovávání dat:
class MyAgent extends Agent {
// Option 1: Delete on completion
async onWorkflowComplete(workflowName, instanceId, result) {
// Process result first, then delete
this.deleteWorkflow(instanceId);
}
// Option 2: Scheduled cleanup (keep recent history)
async cleanupOldWorkflows() {
this.deleteWorkflows({
status: ["complete", "errored"],
createdBefore: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
});
}
// Option 3: Keep all history for compliance/auditing
// Don't call deleteWorkflows() - query historical data as needed
}class MyAgent extends Agent {
// Option 1: Delete on completion
async onWorkflowComplete(
workflowName: string,
instanceId: string,
result?: unknown,
) {
// Process result first, then delete
this.deleteWorkflow(instanceId);
}
// Option 2: Scheduled cleanup (keep recent history)
async cleanupOldWorkflows() {
this.deleteWorkflows({
status: ["complete", "errored"],
createdBefore: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
});
}
// Option 3: Keep all history for compliance/auditing
// Don't call deleteWorkflows() - query historical data as needed
}Obousměrná komunikace
Workflow to Agent
// Direct RPC call (typed)
await this.agent.updateTaskStatus(taskId, "processing");
const data = await this.agent.getData(taskId);
// Non-durable callbacks (may repeat on retry, use for frequent updates)
await this.reportProgress({ step: "process", percent: 0.5 });
this.broadcastToClients({ type: "update", data });
// Durable callbacks via step (idempotent, won't repeat on retry)
await step.reportComplete(result);
await step.reportError("Something went wrong");
await step.sendEvent({ type: "custom", data: {} });
// Durable state synchronization via step (broadcasts to clients)
await step.updateAgentState({ status: "processing" });
await step.mergeAgentState({ progress: 0.5 });// Direct RPC call (typed)
await this.agent.updateTaskStatus(taskId, "processing");
const data = await this.agent.getData(taskId);
// Non-durable callbacks (may repeat on retry, use for frequent updates)
await this.reportProgress({ step: "process", percent: 0.5 });
this.broadcastToClients({ type: "update", data });
// Durable callbacks via step (idempotent, won't repeat on retry)
await step.reportComplete(result);
await step.reportError("Something went wrong");
await step.sendEvent({ type: "custom", data: {} });
// Durable state synchronization via step (broadcasts to clients)
await step.updateAgentState({ status: "processing" });
await step.mergeAgentState({ progress: 0.5 });Agent do Workflow
// Send event to waiting workflow
await this.sendWorkflowEvent("MY_WORKFLOW", instanceId, {
type: "custom-event",
payload: { action: "proceed" },
});
// Approve/reject workflows using convenience methods
await this.approveWorkflow(instanceId, {
reason: "Approved by admin",
metadata: { approvedBy: userId },
});
await this.rejectWorkflow(instanceId, { reason: "Request denied" });// Send event to waiting workflow
await this.sendWorkflowEvent("MY_WORKFLOW", instanceId, {
type: "custom-event",
payload: { action: "proceed" },
});
// Approve/reject workflows using convenience methods
await this.approveWorkflow(instanceId, {
reason: "Approved by admin",
metadata: { approvedBy: userId },
});
await this.rejectWorkflow(instanceId, { reason: "Request denied" });Osvědčené postupy
- Udržujte workflow soustředěné : Jeden workflow na logickou úlohu
- Používejte smysluplné názvy kroků : Pomáhá s laděním a observabilitou
- Nahlaste průběh pravidelně : Udržuje uživatele informované
- Elegantní zpracování chyb : použijte
reportError()před vyvoláním výjimky - Vyčistěte dokončené Workflows : Implementujte zásadu uchovávání dat pro sledovací tabulku
- Zpracování přejmenování vazby Workflows : použijte
migrateWorkflowBinding()při přejmenování vazeb workflow vwrangler.jsonc
Omezení
| Omezení | Limit |
|---|---|
| Maximální počet kroků | 10,000 na workflow (výchozí) / nastavitelné až na 25,000 |
| Velikost stavu | 10 MB na workflow |
| Doba čekání na událost | Maximálně 1 rok |
| Doba provádění kroku | 30 minut na krok |
Workflows nemohou přímo otevírat WebSocket připojení. Použijte broadcastToClients() pro komunikaci s připojenými klienty prostřednictvím Agenta.