本示例演示如何在 Cloudflare Workflows 中使用 waitForEvent() API 引入人工审批步骤。Workflow 由图片上传触发,期间元数据存储在 D1 数据库中。Workflow 然后等待来自 Next.js 前端的外部事件,表示批准或拒绝。批准后,Workflow 使用 Workers AI 生成图片标签并存储到数据库。配套的 Next.js 前端应用便于图片上传和审批流程。
在本 Workflow 中,我们模拟上传图片需要人工审批后才能进行 AI 处理的场景。图片上传到 R2 后,Workflow 执行以下步骤:
- 将图片元数据存储到 D1 数据库。
- 使用
waitForEvent()暂停执行,等待来自 Next.js 前端的外部事件,表示批准或拒绝。 - 如果批准,Workflow 使用 Workers AI 生成图片标签并将标签存储到 D1 数据库。
- 如果拒绝,Workflow 结束,不采取进一步行动。
此模式适用于某些操作在没有明确人工同意的情况下不应继续进行的场景,增加额外的控制和安全层。
本示例包含 Next.js 前端应用,便于图片上传和审批流程。前端提供上传图片、审核以及批准或拒绝的界面。图片上传后,应用触发 Cloudflare Workflow,然后管理后续步骤,包括等待用户审批以及在批准后执行基于 AI 的图片标签。
有关完整前端实现和部署详情,请参阅 GitHub 仓库 ↗ 中的 /nextjs-workflow-frontend 文件夹。
index.ts 文件定义 Cloudflare Workflow 的核心逻辑,负责处理图片上传、等待人工审批以及在批准后执行基于 AI 的图片标签。它扩展 WorkflowEntrypoint 类并实现 run() 方法。
有关 index.ts 文件的完整实现,请参阅 GitHub 仓库 ↗。
export class MyWorkflow extends WorkflowEntrypoint {
db;
async run(event, step) {
this.db = new DatabaseService(this.env.DB);
const { imageKey } = event.payload;
await step.do("Insert image name into database", async () => {
await this.db.insertImage(imageKey, event.instanceId);
});
const waitForApproval = await step.waitForEvent(
"Wait for AI Image tagging approval",
{
type: "approval-for-ai-tagging",
timeout: "5 minute",
},
);
const approvalPayload = waitForApproval.payload;
if (approvalPayload?.approved) {
const aiTags = await step.do("Generate AI tags", async () => {
const image = await this.env.workflow_demo_bucket.get(imageKey);
if (!image) throw new Error("Image not found");
const arrayBuffer = await image.arrayBuffer();
const uint8Array = new Uint8Array(arrayBuffer);
const input = {
image: Array.from(uint8Array),
prompt: AI_CONFIG.PROMPT,
max_tokens: AI_CONFIG.MAX_TOKENS,
};
const response = await this.env.AI.run(AI_CONFIG.MODEL, input);
return response.description;
});
await step.do("Update DB with AI tags", async () => {
await this.db.updateImageTags(event.instanceId, aiTags);
});
}
}
}export class MyWorkflow extends WorkflowEntrypoint<Env, WorkflowParams> {
private db!: DatabaseService;
async run(event: WorkflowEvent<WorkflowParams>, step: WorkflowStep) {
this.db = new DatabaseService(this.env.DB);
const { imageKey } = event.payload;
await step.do('Insert image name into database', async () => {
await this.db.insertImage(imageKey, event.instanceId);
});
const waitForApproval = await step.waitForEvent('Wait for AI Image tagging approval', {
type: 'approval-for-ai-tagging',
timeout: '5 minute',
});
const approvalPayload = waitForApproval.payload as ApprovalRequest;
if (approvalPayload?.approved) {
const aiTags = await step.do('Generate AI tags', async () => {
const image = await this.env.workflow_demo_bucket.get(imageKey);
if (!image) throw new Error('Image not found');
const arrayBuffer = await image.arrayBuffer();
const uint8Array = new Uint8Array(arrayBuffer);
const input = {
image: Array.from(uint8Array),
prompt: AI_CONFIG.PROMPT,
max_tokens: AI_CONFIG.MAX_TOKENS,
};
const response = await this.env.AI.run(AI_CONFIG.MODEL, input);
return response.description;
});
await step.do('Update DB with AI tags', async () => {
await this.db.updateImageTags(event.instanceId, aiTags);
});
}
}
}Workflow 配置在 wrangler.jsonc 文件中定义。此文件包括 R2 存储桶、D1 数据库、Workers AI 和 Workflow 本身的绑定。确保所有必要的绑定和环境变量正确设置以匹配你的 Cloudflare 账户和服务。
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "workflows-waitforevent",
"main": "src/index.ts",
// Set this to today's date
"compatibility_date": "2026-08-17",
"observability": {
"enabled": true,
"head_sampling_rate": 1,
},
"ai": {
"binding": "AI"
},
"workflows": [
{
"name": "workflows-starter",
"binding": "MY_WORKFLOW",
"class_name": "MyWorkflow"
}
],
"r2_buckets": [
{
"bucket_name": "workflow-demo",
"binding": "workflow_demo_bucket"
}
],
"d1_databases": [
{
"binding": "DB",
"database_name": "workflows-demo-d1",
"database_id": "66e4fbe9-06ac-4548-abba-2dc42088e13a"
}
]
}"$schema" = "node_modules/wrangler/config-schema.json"
name = "workflows-waitforevent"
main = "src/index.ts"
# Set this to today's date
compatibility_date = "2026-08-17"
[observability]
enabled = true
head_sampling_rate = 1
[ai]
binding = "AI"
[[workflows]]
name = "workflows-starter"
binding = "MY_WORKFLOW"
class_name = "MyWorkflow"
[[r2_buckets]]
bucket_name = "workflow-demo"
binding = "workflow_demo_bucket"
[[d1_databases]]
binding = "DB"
database_name = "workflows-demo-d1"
database_id = "66e4fbe9-06ac-4548-abba-2dc42088e13a"有关代码库访问、部署说明和参考架构,请访问 GitHub 仓库 ↗。此资源提供有效实现 Workflow 和 Next.js 前端应用所需的所有工具和信息。