テナントを追うワークフロー──Cloudflare Dynamic Workflowsが解いた「最後のピース」

Cloudflareが2026年5月にリリースしたDynamic Workflows。約300行のTypeScriptライブラリが、マルチテナントSaaSやAIエージェント基盤に欠けていた「動的な耐久実行」という最後のパズルを埋めた。その仕組みと意味を読み解く。

·
  • Cloudflare
  • Cloudflare Workers
  • Workflows
  • マルチテナント
  • AIエージェント
  • サーバーレス
フラットイラスト・コミックスタイル。明るいオレンジ背景に、複数の小さなテナントブロック(それぞれ異なる色)が1本の大きなパイプラインに並んで接続されている。パイプラインの中をチェックマーク付きのパケットが流れ、途中で眠るzzz付きのクロックアイコンが挟まる。Cloudflareのオレンジをベースにしたポップなイメージ。

Cloudflareがまた1つ穴を埋めた。

2026年5月1日、Cloudflareエンジニアリングチームが「Introducing Dynamic Workflows: durable execution that follows the tenant」というブログ記事を公開した。メインの発表物は @cloudflare/dynamic-workflows という約300行のTypeScriptライブラリで、MITライセンス、GitHubで公開済みだ。行数だけ見れば小粒に映る。が、この小さなグルーコードが解いたのは、Cloudflareのマルチテナント・プラットフォーム基盤における長年の未解決問題だった。

Cloudflare Workflowsとは何か

そもそも Cloudflare Workflows とは何か、おさらいしておきたい。

Workflows はひとことで言うと、Cloudflare Workers 上で動く「耐久実行エンジン(durable execution engine)」だ。run(event, step) という関数を書くだけで、その中の各ステップが障害に強くなる。ステップは個別にリトライされ、実行状態は自動的に永続化される。「24時間後に再開する」といった長時間スリープも可能で、isolate(Workersのサンドボックス単位)がリサイクルされても、中断した場所から正確に処理が再開される。

Workflowsは2026年2月にGAとなった。V2では1アカウントあたり最大5万の同時インスタンスと毎秒300新規インスタンスをサポートするようになり、AIエージェントの長時間実行を念頭に置いたスケールを実現している。ユースケースは幅広い。ECサイトの注文処理フロー(在庫確認→決済→メール通知→DB更新の各ステップを個別にリトライ可能)、動画トランスコードパイプライン、多段階課金、そして人間の承認待ちを含む長時間エージェントループなどだ。

コスト面でも特徴がある。Workflowsは実際にコードが動いている CPU 時間だけで課金され、外部APIの応答を待つ待機時間は無料だ。LLMの推論を待つ、外部 webhook を待つ、人間の承認を待つ──これら全部タダ。多くのアプリは壁時計上の経過時間のうちほとんどが I/O 待ちだから、実際の請求額は duration-based のプラットフォームより大幅に低くなる。

ひとつの前提が邪魔だった

ただし Workflows には、GAになっても変わらない前提がひとつあった。

ワークフローのコードは、デプロイの一部でなければならない。

wrangler.jsonc に binding を書く。「このバインディングが呼ばれたら MyWorkflow というクラスを実行せよ」と指示する。バインディングは1つ、クラスは1つ、デプロイごとに固定だ。

プラットフォームが自分のコードだけを動かすなら、それで何も困らない。問題は、テナントのコードをCloudflare上で動かしたいとき、つまり**「お客さんのコードがランタイムで変わる」**ときに起きる。

たとえばこんなシナリオを考えてほしい。

AIが各テナント向けにTypeScriptを生成するアプリプラットフォームを作っている。あるいは、各リポジトリが独自のパイプラインを持つ CI/CD サービスを運営している。あるいは、LLMが実行計画を動的に書き、それをエージェントが順番にこなすフレームワークを構築している。いずれのケースも、ワークフローの中身はテナントごと・エージェントごと・リクエストごとに異なる。バインドすべき「単一のクラス」など存在しない。

この問題を Dynamic Workflows が解いた。

Dynamic Workersの流れをくむ「三兄弟」

Dynamic Workflows を理解するには、その前に登場した2つのプリミティブを知っておく必要がある。

Dynamic Workers(2026年4月オープンベータ)は「コンピュート」の動的化を解いた。プラットフォームがランタイムにコードを渡すと、Workersランタイムは独立したサンドボックスをシングルデジット・ミリ秒で起動し、隔離されたワーカーとして実行する。コンテナのように重くなく、メモリも圧倒的に少なく、起動は最大100倍速い。

Durable Object Facetsは「ストレージ」の動的化を解いた。動的にロードされたアプリそれぞれが、自分専用のSQLiteデータベースをオンデマンドで持てるようになった。

Dynamic Workflowsはそれと同じパターンを「耐久実行」に適用したものだ。Dynamic WorkersはコンピュートをDynamicにした。Durable Object FacetsはストレージをDynamicにした。そして Dynamic Workflows は WorkflowEntrypoint をDynamicにする。

ブログではこれを「同じ問題の、3番目の解」と明快に表現している。バインディングのエンベロープを剥いて、正しいテナントコードへ転送するだけ。やっていることは同じ。適用先が違う。

300行のライブラリが実現すること

@cloudflare/dynamic-workflows の役割は、1つの Worker(Worker Loader)がすべての create() 呼び出しを異なるテナントコードにルーティングし、さらにWorkflowsエンジンが run(event, step) を呼び返すときも正しいテナントコードに届けることだ。

仕組みはこうだ。テナントがワークフローを作成するとき、テナントから見えるバインディングは普通の Workflow バインディングに見える。だが実際には、Worker Loader の DynamicWorkflowBinding(WorkerEntrypoint のサブクラス)への RPC 呼び出しになっている。このバインディングがペイロードにテナントIDをこっそり付与し、本物の Workflows バインディングへ転送する。

エンジンがワークフローのステップを実行するとき、wrangler.jsonc に登録されたクラス(createDynamicWorkflowEntrypoint が生成したもの)がエンベロープを解析し、loadRunner コールバックへテナントIDを渡す。コールバックはテナントのコードを R2 からフェッチして返す。Worker Loader はアイソレートをIDでキャッシュするため、数時間にまたがる複数ステップも同じ Dynamic Worker を再利用する。アイソレートが追い出されても、次の step.do() でコードを再取得してそのまま継続できる。テナントのワークフローには何が起きたかわからない。

テナント側のコードは完全にピュアなWorkflows実装で書けばいい。

import { WorkflowEntrypoint } from 'cloudflare:workers';

export class TenantWorkflow extends WorkflowEntrypoint {
  async run(event, step) {
    const result = await step.do('fetch-data', async () => {
      return fetch(`https://api.example.com/data/${event.payload.id}`)
        .then(r => r.json());
    });

    await step.sleep('wait-for-approval', '24 hours');

    await step.do('process', async () => {
      // 24時間後でも、isolateがなくなっていても、ここから再開される
      return processData(result);
    });
  }
}

step.do()step.sleep()step.waitForEvent() ─ すべてが普通の Workflows と同じように動く。自分がディスパッチされているとテナントは知らない。

誰のためのプリミティブか

Cloudflare が示す典型的なユースケースは3つある。

まずマルチテナント SaaS。各テナントが独自のオートメーションを定義する──オンボーディングシーケンス、承認チェーン、課金リトライロジックなどを、テナントごとに別の Workflow を事前にデプロイすることなく耐久実行できる。

次にAIエージェントフレームワーク。LLMがランタイムに多段階の実行計画を生成し、それをエージェントが順番にこなしていく。プランの各ステップはリトライ可能で、ツール呼び出し間で自由にスリープできる。人間の承認を待つ step.waitForEvent() も待機コスト無料で使える。エージェントがプランを「書き」、プラットフォームがそのプランを「走らせる」──そのどちらもが事前にコードをデプロイしなくていい。

3つ目はマルチテナントジョブシステム。各顧客が独自の処理ロジック(データ変換、webhookチェーン、スケジュールタスクなど)を投入し、それぞれのステップが進捗を永続化しながらリトライされる。自前のオーケストレーターを作らずに済む。

Cloudflareがブログで持ち出した事例として印象的なのは CI/CD だ。CIプラットフォームの本質は「リポジトリごとの設定ファイル(.yml)を受け取り、ジョブをディスパッチするシステム」に他ならない。各PRがスポーンするインスタンスは「完走しなければならない・クラッシュを生き延びなければならない・flaky なステップをリトライしなければならない・ログをストリーミングしなければならない・承認のために一時停止できなければならない」という要件を持つ。Dynamic Workflows はそれをそのまま実現する。しかもVM起動・ベースイメージのプル・リポジトリのクローン・依存のインストールで1分以上かかっていた従来のCIと違い、Dynamic Workers上のステップは数ミリ秒で起動する。

「すべてのバインディングを動的に」という設計思想

Cloudflare の設計思想は一貫している。公式ブログはこう述べる。「現在WorkersがExportするすべてのバインディングは、動的なカウンターパートへと向かっている」と。キュー、キャッシュ、データベース、オブジェクトストア、AIバインディング、MCPサーバー──テナントごと・エージェントごと・リクエストごとに、ゼロのアイドルコストで動的にディスパッチできるようにする。

このビジョンが実現すると、マルチテナントSaaSのユニットエコノミクスが根本から変わる。アイドルのテナントはほぼゼロコスト、アクティブなテナントはアイソレートレベルでハードウェアを共有する。Cloudflareの主張によれば、「これまで数千の有料顧客が限界だったプラットフォームが、数千万規模を合理的に提供できるようになる」。

試すには

@cloudflare/dynamic-workflows は npm で公開済みだ。

npm install @cloudflare/dynamic-workflows

Dynamic Workers が前提で、Workers Paid プランのオープンベータとして現在利用可能だ。ドキュメントは Cloudflare の公式 Dynamic Workers ドキュメントサイトに動的ワークフローのガイドが用意されている。


個人的に気になるのは、これが「エージェントが書いたコードを、エージェントが耐久実行する」インフラになり得る点だ。LLMがTypeScriptのワークフローコードを生成し、それが即座に Cloudflare のグローバルネットワーク上で動く。ステップが失敗してもリトライされ、承認待ちがあっても休眠してコストをかけない。テナントは何十万いても、アイドル中は何も払わない。

ひとつのプリミティブが埋まるたびに、Cloudflareのプラットフォームはまた一段と「インフラを書かなくていい理由」を増やしていく。

Last updated