失敗には、コンテナーが作業を開始していないものと、作業がすでに始まっている可能性があるものがあります。回復の仕方はそれぞれ異なります。
同じ サンドボックス ID でも、あとから 新しいコンテナー を使うことがあります。以前のコンテナーのプロセス、ターミナル、ローカルファイルは、自動では戻りません。Sandbox のライフサイクル と プロセスの存続期間 を参照してください。
クラス一覧は Errors API です。症状の表は トラブルシューティング です。
コンテナーの準備ができていない場合、SDK は ContainerUnavailableError(CONTAINER_UNAVAILABLE)を投げることがあります。操作はコンテナー内では実行されていません。
コールドスタート、アイドル停止のあと、またはデプロイ中によく起きます。
エラーの context には retryable: true、reason(例: container_starting)、任意の retryAfterMs が含まれます。バックオフします(ある場合は retryAfterMs を使います)。その後、同じ種類の処理を再試行します。
コンテナーが作業を開始したあとに起きる失敗には、この「常に再試行する」ルールを使わないでください。
import { ContainerUnavailableError } from "@cloudflare/sandbox";
try {
const process = await sandbox.exec(["npm", "install"], {
cwd: "/workspace/app",
});
await process.waitForExit();
} catch (error) {
if (error instanceof ContainerUnavailableError) {
// Safe to retry the whole operation after backoff.
}
}import { ContainerUnavailableError } from "@cloudflare/sandbox";
try {
const process = await sandbox.exec(["npm", "install"], {
cwd: "/workspace/app",
});
await process.waitForExit();
} catch (error) {
if (error instanceof ContainerUnavailableError) {
// Safe to retry the whole operation after backoff.
}
}コンテナーが操作を受け付けたあと、失敗すると途中結果が残ることがあります。プロセスが動いている、ファイルが存在する、バックアップが始まっている、などです。
OperationInterruptedError は、呼び出しがすでに進行中にコンテナーまたはサンドボックスが変わったことを意味します。作業は開始済みの可能性があります。
エラーの reason と retryable を使います(フィールドは Errors API を参照してください)。手順が状態を変える場合は、同じ手順を再実行する前に、サンドボックスまたは自分側の記録を確認します。
RPCTransportError は、呼び出し中に SDK が現在のコンテナーとの接続を失ったことを意味します。後続の呼び出しは、同じコンテナーに対して成功することがあります。
これは、中断した呼び出しが何もしなかったことを 意味しません。同じ作業を繰り返す前に、チェックポイントと二重実行しても安全な手順を使うか、状態を確認してください。診断用の kind 値は Errors API にあります。
プロセス ID とターミナル ID は、サンドボックス ID の 現在の コンテナーに属します。停止または置き換えのあと、古いハンドルへの呼び出しは StaleProcessHandleError または StaleTerminalHandleError を投げます。getProcess、getTerminal、listProcesses、listTerminals はコンテナーを起動しません。コンテナーが動いていない場合、または現在のコンテナーに未知の ID の場合は null または [] を返します。これは例外ではありません。
リソース ID だけでなく、ジョブ(コマンド、cwd、env、チェックポイント)を保存します。古いハンドルがなくなったら、新しい exec または createTerminal を開始します。
output()、waitForExit()、waitForLog()、waitForPort()、logs() のタイムアウトと AbortSignal は、その待機またはストリームだけ を終了します。プロセスは終了しません。ターミナル出力のキャンセルは PTY を終了しません。
リソースを止めたいときは process.kill()、または terminal.interrupt() / terminal.terminate() を使います。よく出るエラーは ProcessWaitTimeoutError、ProcessAbortedError です。
不正な cwd や環境変数、存在しない実行ファイル、同様のリクエストの問題は、値を変えるまで失敗します。同じ不正なリクエストを再試行しないでください。よく使うクラスは InvalidProcessCwdError、InvalidProcessEnvironmentError、ProcessSpawnFailedError です。
Worker パッケージとコンテナーイメージが一致していない、イメージが起動できない、Worker とコンテナーのあいだのセットアップが失敗した、という意味の失敗があります。
| 兆候 | 対応 |
|---|---|
RuntimeControlProtocolError(例: unsupported-protocol-version、不足または不正なメタデータ) |
Worker パッケージとコンテナーイメージを、同じ @cloudflare/sandbox@next 系列からデプロイします。プレビューと安定版のパッケージを混ぜないでください。 |
| イメージが誤りまたは不足している、あるいは準備完了前にコンテナーが終了する | wrangler、イメージ、またはエントリポイントを直します。同じアプリケーション呼び出しの再試行では直りません。 |
| アカウントまたはロケーションの容量制限 | 同時実行を減らすか、制限を上げます。プラットフォームの制限 を参照してください。 |
カタログの詳細は Worker とコンテナーイメージの不一致 です。
これらは、遅い起動(ContainerUnavailableError)とは違います。両方に同じバックオフと再試行のループを使わないでください。
エラー: ContainerUnavailableError
バックオフしたあと、作業単位全体(例: セットアップと exec)を再実行します。チェックポイントなしで途中のステップだけを実行しないでください。
- ジョブとチェックポイントを永続化します(役立つあいだはプロセス ID またはターミナル ID も)。
- 後続のリクエストでは、ID が残っている場合に
getProcessまたはgetTerminalを呼び出します。 - ハンドルが取れたら続行します(ログ、接続、待機)。
nullまたは古いハンドルのエラーになったら、チェックポイントからやり直します。ContainerUnavailableErrorになったら、バックオフして新しい操作で続行します。
エラー: OperationInterruptedError
reason と retryable を読みます。呼び出しが何かを変えている可能性がある場合は、繰り返す前に状態を確認します。
エラー: RPCTransportError
診断が必要なら kind を記録します。進行中の作業は実行済みの可能性があると考えます。チェックポイントまたは確認から続行し、ジョブがまだ必要なら新しい操作を開始します。
エラー: ProcessWaitTimeoutError、ProcessAbortedError
観察を続ける(getProcess と logs({ since }))か、kill でプロセスを止めます。待機が終わったからといって、プロセスが終了したとは限りません。
エラー: InvalidProcessCwdError、InvalidProcessEnvironmentError、ProcessSpawnFailedError、および同様のエラー
パス、環境、またはコマンドを直します(バイナリが無い場合はイメージ内のファイルも)。値を変えずに再試行しないでください。
状況: デプロイ後、プロトコルまたはセットアップのエラーで呼び出しが失敗する、あるいはコンテナーが使える状態にならない。
エラー / 兆候: RuntimeControlProtocolError、誤ったイメージ、準備完了前のコンテナー終了
すること: Worker パッケージとコンテナーイメージを、同じ @cloudflare/sandbox@next 系列から再デプロイします。イメージ名とエントリポイントを確認します。
しないこと: 遅いコンテナー起動と同じ扱いをして、バックオフだけする。
import {
ContainerUnavailableError,
OperationInterruptedError,
RPCTransportError,
StaleProcessHandleError,
ProcessWaitTimeoutError,
ProcessAbortedError,
} from "@cloudflare/sandbox";
try {
const process = await sandbox.exec(["npm", "test"], {
cwd: "/workspace/app",
});
const result = await process.output({ encoding: "utf8" });
console.log(result.exitCode, result.stdout);
} catch (error) {
if (error instanceof ContainerUnavailableError) {
// Container never started the work — back off, then try the work again.
} else if (error instanceof StaleProcessHandleError) {
// Previous container — start again from what you stored about the work.
} else if (error instanceof OperationInterruptedError) {
// Work may have started — read reason/retryable and check state before repeating.
} else if (error instanceof RPCTransportError) {
// Lost contact during the call — a later call may work; this call may already have run.
} else if (
error instanceof ProcessWaitTimeoutError ||
error instanceof ProcessAbortedError
) {
// Wait ended only — process may still be running.
} else {
throw error;
}
}import {
ContainerUnavailableError,
OperationInterruptedError,
RPCTransportError,
StaleProcessHandleError,
ProcessWaitTimeoutError,
ProcessAbortedError,
} from "@cloudflare/sandbox";
try {
const process = await sandbox.exec(["npm", "test"], {
cwd: "/workspace/app",
});
const result = await process.output({ encoding: "utf8" });
console.log(result.exitCode, result.stdout);
} catch (error) {
if (error instanceof ContainerUnavailableError) {
// Container never started the work — back off, then try the work again.
} else if (error instanceof StaleProcessHandleError) {
// Previous container — start again from what you stored about the work.
} else if (error instanceof OperationInterruptedError) {
// Work may have started — read reason/retryable and check state before repeating.
} else if (error instanceof RPCTransportError) {
// Lost contact during the call — a later call may work; this call may already have run.
} else if (
error instanceof ProcessWaitTimeoutError ||
error instanceof ProcessAbortedError
) {
// Wait ended only — process may still be running.
} else {
throw error;
}
}@cloudflare/sandbox のクラスに対する instanceof を優先してください。表の全体は Errors API です。