第17章: Cloudflare Workflows による耐久バッチ実行(実践チュートリアル)
従来のサーバーレス関数では「処理時間が数十秒を超えるとタイムアウトする」「外部API障害で途中で落ちたら最初から全処理をやり直し」という課題がありました。
Cloudflare Workflows は、コード内に複数のステップ(step.do())やスリープ(step.sleep())を記述するだけで、途中でサーバーが再起動しても 完了済みステップの結果を保持したまま、失敗したステップだけを自動再試行する耐久性実行エンジン です。
本チュートリアルで作成するもの
- マルチステップ耐久ワークフロー:
- Step 1: 外部APIからデータ収集・集計(失敗時は自動指数バックオフ再試行)
- Step 2: 指定時間(例: 1分間、または3日間)のコストゼロ待機(
step.sleep) - Step 3: 完了通知の送信
- CLI操作:
wrangler workflows triggerによるCLIからの直接実行wrangler workflows describeによるステップ進捗の追跡
Step 1: wrangler.jsonc の設定
プロジェクトの設定ファイルに workflows 定義を追加します。
{ "$schema": "node_modules/wrangler/config-schema.json", "name": "durable-workflow-demo", "main": "src/index.ts", "compatibility_date": "2024-10-22", "compatibility_flags": [ "nodejs_compat" ], "workflows": [ { "name": "report-pipeline", "binding": "REPORT_WORKFLOW", "class_name": "ReportWorkflow" } ]}型定義を更新します。
npx wrangler typesStep 2: ワークフロークラスの実装(src/index.ts)
import { WorkflowEntrypoint, WorkflowStep, WorkflowEvent } from 'cloudflare:workers';
// ワークフロー起動パラメータの型定義type WorkflowParams = { reportId: string; recipientEmail: string;};
// 1. 耐久ワークフロー本体export class ReportWorkflow extends WorkflowEntrypoint<Env, WorkflowParams> { async run(event: WorkflowEvent<WorkflowParams>, step: WorkflowStep) { const { reportId, recipientEmail } = event.payload;
// ステップ1: データ集計処理(失敗した場合は自動で3回まで指数バックオフ再試行) const reportData = await step.do( 'aggregate-report-data', { retries: { limit: 3, delay: '5 seconds', backoff: 'exponential' } }, async () => { console.log(`[Step 1 開始] レポートID: ${reportId} のデータ集計中...`); // 何らかの外部API呼び出しやD1クエリのシミュレーション return { totalUsers: 1450, revenue: 350000, generatedAt: new Date().toISOString(), }; } );
// ステップ2: 待機(CPUリソースを一切消費せず、安全にスリープ) // ※ チュートリアル検証のため10秒待機(実務では '1 hour' や '3 days' と指定可能) console.log('[Step 2] 一時待機に入ります(10秒間)...'); await step.sleep('wait-for-cooloff', '10 seconds');
// ステップ3: 集計結果のレポート送信 await step.do('send-final-report', async () => { console.log(`[Step 3 開始] ${recipientEmail} へ集計レポートを送信します`); console.log(`集計結果: ユーザー数=${reportData.totalUsers}, 売上=${reportData.revenue}`); return { sent: true }; });
console.log(`[ワークフロー完了] レポート ${reportId} の全パイプラインが正常終了しました`); }}
// 2. HTTPエンドポイント(Webからワークフローをキックする場合)export default { async fetch(req: Request, env: Env): Promise<Response> { const url = new URL(req.url);
if (url.pathname === '/trigger') { const instance = await env.REPORT_WORKFLOW.create({ params: { reportId: `REP_${Date.now()}`, recipientEmail: 'boss@example.com', }, });
return Response.json({ message: 'ワークフローを起動しました', instanceId: instance.id, }); }
return new Response('Use /trigger to start workflow'); }};Step 3: ローカル開発環境での動作確認
ローカルサーバーを起動します。
npx wrangler dev別ターミナルからワークフローを起動します。
curl http://localhost:8787/triggerレスポンス例:
{ "message": "ワークフローを起動しました", "instanceId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}サーバーのターミナルログに、各ステップが順序通り、10秒のスリープを挟んで実行される様子がリアルタイムに表示されます。
Step 4: 本番デプロイとCLIによる運用追跡
# 本番へデプロイnpx wrangler deploy
# 1. 登録済みワークフロー一覧を確認npx wrangler workflows list
# 2. CLIから直接パラメータを渡して手動実行npx wrangler workflows trigger report-pipeline \ --params '{"reportId":"MANUAL_01","recipientEmail":"admin@example.com"}'
# 3. 実行状況(実行中 / 完了 / ステップ進捗)を確認npx wrangler workflows describe report-pipeline <INSTANCE_ID>まとめ
- ステップ分割(
step.do): 処理が分割され、各ステップの戻り値が永続化されます。 - 長期間スリープ(
step.sleep): 数時間〜数日間の待機でもサーバー費用は0円。 - CLI操作:
wrangler workflowsコマンドでCLIからワンライナーでテスト・ステータス確認が可能。
💡 用語解説コラム
[!NOTE] 耐久性実行 (Durable Execution)
コードの途中でサーバー停止や障害が起きても、完了済みのステップの状態を保持し、自動的に直前のステップから再開・再試行される実行アーキテクチャ。
[!NOTE] 指数バックオフ (Exponential Backoff)
エラー時の再試行間隔を1秒、2秒、4秒、8秒…と倍々に延ばしていく手法。障害中の相手サーバーへの負荷集中を防ぎます。