この例では、Cloudflare Workflows の waitForEvent() API を使い、ヒューマンインザループ(人手承認)のステップを導入します。Workflow は画像のアップロードで起動し、メタデータを D1 データベースに保存します。その後、ユーザーの承認を待ち、承認されると Workers AI で画像タグを生成してデータベースに保存します。付属の Next.js フロントエンドアプリケーションで、画像のアップロードと承認を行います。
この Workflow では、アップロードした画像に、AI 処理の前に人手承認が必要なシナリオを想定します。画像は R2 にアップロードされ、その後 Workflow が次のステップを実行します。
- 画像のメタデータを D1 データベースに保存します。
waitForEvent()で実行を一時停止し、Next.js フロントエンドから送られる承認または拒否の外部イベントを待ちます。- 承認された場合、Workflow は Workers AI で画像タグを生成し、そのタグを D1 データベースに保存します。
- 拒否された場合、Workflow はそれ以上の処理をせずに終了します。
明示的な人の同意なしに進めたくない処理がある場合に役立つパターンです。制御と安全性を一段高められます。
この例には、画像のアップロードと承認を行う Next.js フロントエンドアプリケーションが含まれます。フロントエンドは、画像のアップロード、確認、承認または拒否の画面を提供します。画像をアップロードすると、アプリケーションが Cloudflare Workflow を起動します。以降のステップ(ユーザー承認の待機と、承認後の AI 画像タグ付け)は Workflow が管理します。
フロントエンド実装とデプロイの詳細は、GitHub リポジトリ ↗ の /nextjs-workflow-frontend フォルダを参照してください。
index.ts ファイルは、画像アップロードの処理、人手承認の待機、承認後の AI 画像タグ付けを担当する Cloudflare Workflow の中核ロジックを定義します。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-09-20",
"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-09-20"
[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 フロントエンドアプリケーションを実装するために必要なツールと情報が揃っています。