サンドボックスプラグインは、サンドボックスランナーが提供する分離されたランタイムで実行されます。マーケットプレイスとレジストリのインストールは常にサンドボックスで実行され、emdash() インテグレーションの sandboxed: [] にリストされたプラグインも同様です。plugins: [] にリストされたプラグインはサーバープロセスで実行され、ランナーを使用しません。
ランナーはデプロイメントプラットフォームに依存します。Cloudflare Workersでは、各プラグインはWorker Loaderバインディングを通じて作成される Dynamic Worker として実行されます。Node.jsでは、サーバーがオープンソースのWorkersランタイムである workerd を子プロセスとして起動し、各プラグインをその中のサービスとして実行します。emdash() の sandboxRunner オプションでランナーを選択します。これがないと、sandboxed: [] のプラグインはロードされず、設定された marketplace は「Marketplace requires sandboxRunner to be configured」でビルドを失敗させます。
以下の表は、各ランナーが必要とするものと適用するものをまとめています。
| Cloudflare Workers | Node.js | |
|---|---|---|
sandboxRunner | @emdash-cms/cloudflare の sandbox() | "@emdash-cms/sandbox-workerd/sandbox" |
| 要件 | Workers Paidプラン、worker_loaders バインディング、Workerエントリポイントからエクスポートされた PluginBridge | workerd パッケージ |
| データベースアクセス | DB D1バインディング(設定されたアダプターに依存しない) | 設定されたデータベース |
| 適用される制限 | CPU時間、サブリクエスト、ウォールタイム | ウォールタイム |
Cloudflare Workers
Dynamic Workersは Workers Paidプラン で利用できます。ランナーには以下のバインディングとエントリポイントエクスポートが必要です。*-cloudflare テンプレートには両方が含まれています。
-
Worker Loaderバインディングを
wrangler.jsoncに追加します。ランナーはLOADERという名前で読み取ります:{ "worker_loaders": [ { "binding": "LOADER", }, ], } -
Workerエントリポイントから
PluginBridgeをエクスポートし、mainをそのファイルに向けます。PluginBridgeはサンドボックスプラグインがコンテンツ、メディア、ストレージ、メールにアクセスするためのエントリポイントです。ランナーはエントリモジュールのエクスポートからこれを検索します:import handler, { createScheduledHandler, PluginBridge } from "@emdash-cms/cloudflare/worker"; export { PluginBridge }; export default { ...handler, scheduled: createScheduledHandler(), } satisfies ExportedHandler;{ "main": "./src/worker.ts", } -
emdash()インテグレーションでランナーを選択します:import { d1, r2, sandbox } from "@emdash-cms/cloudflare"; emdash({ database: d1({ binding: "DB" }), storage: r2({ binding: "MEDIA" }), sandboxRunner: sandbox(), });
Node.js
-
ピア依存関係である
workerdとともにランナーをインストールします:npm install @emdash-cms/sandbox-workerd workerdworkerdパッケージは、オプショナル依存関係を通じて現在のプラットフォーム(x64のLinux、macOS、Windows、arm64のLinuxおよびmacOS)用のバイナリをインストールします。サーバーが実行されるプラットフォームで、オプショナル依存関係を有効にしてインストールしてください。マルチステージDockerビルドでは、ランタイムステージと同じプラットフォームのステージでインストールを実行してください。 -
emdash()インテグレーションでランナーを選択します:import { sqlite } from "emdash/db"; emdash({ database: sqlite({ url: "file:./data/emdash.db" }), sandboxRunner: "@emdash-cms/sandbox-workerd/sandbox", }); -
開発用に、
miniflareを開発依存関係としてインストールします:npm install -D miniflareNODE_ENVがdevelopment(astro devが設定)でminiflareがインストールされている場合、ランナーはプラグインをMiniflareに渡し、Miniflareが自身のworkerdプロセスを管理します。以下のクラッシュポリシーは適用されません。astro previewはNODE_ENVをproductionに設定し、node ./dist/server/entry.mjsは未設定のままにします。両方ともworkerdを使用します。
workerd プロセスの動作方法
EmDashはサイトへの最初のリクエスト時の初期化中に workerd を起動し、サンドボックスプラグインがロードされた後、プラグインサービスが応答するまで最大10秒待ちます。管理画面からプラグインのインストールまたは更新を行うと再起動されます。workerd がstdoutまたはstderrに書き出すすべてのものは、[emdash:workerd] プレフィックス付きでサーバーの出力に表示されます。
プラグインサービスは 127.0.0.1 でリッスンし、サーバーへの戻りチャネルはUnixドメインソケット(Windowsでは 127.0.0.1 TCPポート)です。インバウンドポートを開く必要はありません。
子プロセスはサーバーの環境から PATH、HOME、TMPDIR、TMP、TEMP、LANG、LC_ALL のみを受け取るため、サーバー環境のシークレットはサンドボックスに入りません。より多くの変数を渡すには、EMDASH_WORKERD_PASSTHROUGH_ENV をカンマ区切りの変数名リストに設定してください。
workerd が予期せず終了した場合、ランナーは [emdash:workerd] workerd exited with <reason> をログに記録し、次の呼び出し時に再起動します。遅延は1秒から始まり、30秒まで倍増します。60秒以内に workerd が5回以上クラッシュした場合、ランナーは再起動を停止し、[emdash:workerd] workerd crashed 5 times in 60 seconds, giving up をログに記録します。それ以降、サーバーが再起動されるまで、すべてのサンドボックスプラグインフックとルートは Plugin sandbox unavailable for <plugin>: workerd is not running で失敗します。サーバーへの SIGTERM は workerd も終了させます。
リソース制限
各ランナーはプラグイン呼び出しごとに同じ制限セットを適用します。制限は固定されており、emdash() インテグレーションにはそれらのオプションはありません。
| 制限 | 値 | Cloudflare Workers | Node.js |
|---|---|---|---|
| CPU時間 | 50 ms | Worker Loaderが適用;プラグインは制限に達するとスローする | 適用されない |
| サブリクエスト | 10 | Worker Loaderが適用;プラグインは制限に達するとスローする | 適用されない |
| メモリ | 128 MB | プラグインごとには適用されない;プラットフォームのアイソレートメモリ上限が適用 | 適用されない |
| ウォールタイム | 30 s | ランナーが適用 | ランナーが適用 |
フックまたはルートがウォールタイム制限を超えた場合、呼び出しは Plugin <id> exceeded wall-time limit of 30000ms during hook:<name>(または route:<name>)で失敗します。フックの場合、EmDashは EmDash: Sandboxed plugin <id> プレフィックスで失敗をログに記録し、そのプラグインの結果なしでリクエストを続行します。制限を超えたプラグインルートは呼び出し元に対して失敗します。
ランナーが利用できない場合
設定されたランナーでも利用できない場合があります:Cloudflare Workersで worker_loaders バインディングまたは PluginBridge エクスポートが欠落している場合、Node.jsで workerd がインストールされていないかそのバイナリが実行されない場合です。EmDashはランタイム起動時に以下の警告をログに記録します:
EmDash: Plugin sandbox is configured but not available on this platform. Sandboxed plugins will not be loaded. If using @emdash-cms/sandbox-workerd/sandbox, ensure workerd is installed.
sandboxed: [] のプラグインはロードされず、インストール済みのマーケットプレイスおよびレジストリプラグインは実行されず、管理画面からの新規インストールはエラーコード SANDBOX_NOT_AVAILABLE で失敗します。サイトの残りの部分は影響を受けません。
サンドボックスプラグインをインプロセスで実行する
emdash() で sandbox: false を設定すると、sandboxed: [] のプラグインとインストール済みのマーケットプレイスプラグインを、分離や制限なしでサーバープロセスで実行します。これはプラグインのバグとサンドボックスのバグを区別するためのデバッグオプションです。以下の設定はNode.jsサイトでサンドボックスをオフにします:
emdash({
sandboxRunner: "@emdash-cms/sandbox-workerd/sandbox",
sandbox: false,
});
Cloudflare Workersでは、ランタイムは sandbox: false is not supported in Cloudflare Workers で起動を拒否します。
トラブルシューティング
各エントリは、サーバーがログに記録するメッセージ、または管理画面が返すエラーコードで始まります。
“Plugin sandbox is configured but not available on this platform”
Cloudflare Workersでは、両方の要件を確認してください:wrangler.jsonc に LOADER という名前の worker_loaders バインディングがあること、main が PluginBridge をエクスポートするファイルを指していること。バインディングのデプロイにはWorkers Paidプランが必要です。
Node.jsでは、ランナーが使用するバイナリを実行します:
npx workerd --version
コマンドが失敗した場合、workerd が node_modules にないか、インストールされたバイナリがこのプラットフォームで実行されません。ターゲットプラットフォームでオプショナル依存関係を有効にして再インストールしてください。
“workerd failed to start within 10 seconds”
子プロセスは起動しましたが、そのプラグインサービスが10秒以内に応答しませんでした。このメッセージの前の [emdash:workerd] プレフィックス付きの行には、設定エラーや起動エラーを含む workerd 自体の出力が含まれています。ランナーは次の呼び出し時に再試行します。
“workerd crashed 5 times in 60 seconds, giving up”
ランナーは workerd の再起動を停止しました。このメッセージの前の [emdash:workerd] workerd exited with <reason> 行は、各クラッシュの終了コードまたはシグナルを示します。原因を修正してからサーバーを再起動してください。
プラグインインストール時の SANDBOX_NOT_AVAILABLE
ランナーが欠落しているか利用できないため、管理画面のインストールリクエストが拒否されました。プラットフォーム用にランナーを設定するか、上記の起動警告の原因を修正して再デプロイしてください。