# テナントの数だけワークフロー！Cloudflare Dynamic Workflows が登場したよ！

やっほー、しぃちゃんだよ！今日はマルチテナントで消耗してきたエンジニアさんが泣いて喜ぶ発表を見つけちゃった。ワクワクするから一緒に見ていこうね！

## なにが発表されたの？

Cloudflare の Blog で、[Dynamic Workflows](https://developers.cloudflare.com/dynamic-workers/usage/dynamic-workflows/) っていう新しいライブラリが発表されたよ。ひとことで言うと、「テナントごとにまったく違うワークフローのコードを、実行時に動的にルーティングして耐久実行する」ためのしくみなの。

これは [Dynamic Workers](https://blog.cloudflare.com/dynamic-workers/) の上に載る、たった約 300 行の TypeScript ライブラリなんだって。1 つの Worker が、リクエストのたびに違うテナントのコードを読み込んでワークフローを走らせてくれるの。しかも 100 万規模のユニークなワークフローを、アイドルコストほぼゼロで扱えるって書いてあるよ。

## 今までどうだったの？

これまでの [Cloudflare Workflows](https://developers.cloudflare.com/workflows/) は、ワークフローのコードをデプロイの一部として持っておく必要があったの。つまり「この処理はこのクラス」ってあらかじめ結びつけておくスタイルだね。

でもこれ、マルチテナントだと途端に困っちゃう。原文がうまいこと言ってるんだけど、

> the workflow is different for every tenant, every agent, every request. There is no single class to bind.

つまりテナントごと・エージェントごと・リクエストごとに処理が違うと、「結びつける単一のクラス」なんて存在しないの。エージェントが生成したコードや、ユーザーが書いたパイプラインを走らせたいとき、この静的な縛りがずっと壁になってたんだね。

## これで何が変わるの？

Dynamic Workflows を使うと、テナント固有のワークフローコードを実行時にディスパッチできるようになるよ。プラットフォーム側は Worker Loader を持つ 1 つの Worker を用意するだけ。あとはテナントが書いたコードを、必要なときに読み込んで走らせればいいの。

うれしいのは、テナント側から見ると「ふつうの Workflows」にしか見えないところ。`env.WORKFLOWS.create(...)` を呼ぶだけで、裏側でしぃちゃんたちの見えないところにテナント情報がくっついて、ちゃんと正しいコードにルーティングされるんだよ。

- エージェント基盤: モデルが書いた `run(event, step)` をそのまま耐久実行できる
- SDK / フレームワーク: ユーザーが書いたワークフローロジックを動かせる
- CI/CD: リポジトリごとに違うパイプライン定義を、そのまま実行できる

## 深く潜ってみよう

しくみは 3 層構造になってるの。上から順に、ワークフローエンジン → Worker Loader → テナントの Dynamic Worker コード、だよ。

流れをざっくり言うと、こんな感じ:

1. Worker Loader がリクエストを受けてテナントを特定し、そのコードを読み込む
2. テナントが `create()` を呼ぶと、RPC で Worker Loader に上がって、テナント情報の「封筒(メタデータエンベロープ)」が payload に足される
3. エンジンがその封筒ごとイベントを永続化してスケジュール
4. 実行時にエンジンが登録済みクラスの `run(event, step)` を呼び、封筒をほどいて正しいテナントコードへ

Worker Loader はテナント ID でコードをキャッシュするから、複数ステップのワークフローは同じ isolate を再利用するの。途中で isolate が退避されても、次のステップでまた読み込むだけだから透過的なんだって。[Dynamic Workers](https://blog.cloudflare.com/dynamic-workers/) は数ミリ秒(single-digit milliseconds)で起動して、メモリも数 MB しか使わないから、アイドルなテナントのコストはほぼゼロなの。

標準の Workflows の機能はぜんぶそのまま使えるよ。`step.sleep()` での休眠、`step.waitForEvent()` での人間の承認待ち、リトライ、`.status()` / `.pause()` / `.resume()` なんかも透過的に効くの。設定は wrangler にこう書くだけ:

```
"workflows": [
  { "name": "dynamic-workflow", "binding": "WORKFLOW", "class_name": "DynamicWorkflow" }
]
```

1 個だけ注意ポイント。メタデータはあくまで「ルーティングのヒント」で、認可(authorization)じゃないの。テナントは `instance.status()` から読み返せちゃうから、秘密の情報は入れちゃダメだよ。

ちなみにこの Dynamic Workflows は、Cloudflare が進めてる「なんでも動的に」戦略の 1 ピースなんだって。動的なコンピュートの Dynamic Workers、動的なストレージの [Durable Object Facets](https://blog.cloudflare.com/durable-object-facets-dynamic-workers/)、動的なソース管理の [Artifacts](https://blog.cloudflare.com/artifacts-git-for-agents-beta/)、そして動的な耐久実行がこの Dynamic Workflows、っていう並びなの。

## まとめ

- Cloudflare の Blog が、テナントごとに違うワークフローを実行時ルーティングできるライブラリ Dynamic Workflows を発表
- Dynamic Workers の上に載る約 300 行の TypeScript で、100 万規模のワークフローをアイドルコストほぼゼロで
- テナント側は `env.WORKFLOWS.create()` を呼ぶだけ。`step.sleep()` や `step.waitForEvent()` などの機能も透過的に動く
- メタデータはルーティングのヒントで認可じゃない。秘密は入れない
- `@cloudflare/dynamic-workflows` は MIT ライセンスで npm 公開、Workers Paid プランで使えて Dynamic Workers はオープンベータ

マルチテナントで「テナントごとに違う処理をどう走らせるか」に頭を抱えてた、エージェント基盤や CI/CD、ノーコードプラットフォームを作ってる人にドンピシャな発表だよ！
