INTEGRITY Dokumentace

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í:

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

  1. Udržujte workflow soustředěné : Jeden workflow na logickou úlohu
  2. Používejte smysluplné názvy kroků : Pomáhá s laděním a observabilitou
  3. Nahlaste průběh pravidelně : Udržuje uživatele informované
  4. Elegantní zpracování chyb : použijte reportError() před vyvoláním výjimky
  5. Vyčistěte dokončené Workflows : Implementujte zásadu uchovávání dat pro sledovací tabulku
  6. Zpracování přejmenování vazby Workflows : použijte migrateWorkflowBinding() při přejmenování vazeb workflow v wrangler.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.

Dokumentace Workflows

Seznamte se se základy Cloudflare Workflows.

Ukládání a synchronizace stavu

Ukládejte a synchronizujte stav agenta.

Plánování úloh

Časově řízené spouštění úloh.

Lidský zásah

Postupy schvalování a vzory ruční intervence.