Loading...
Loading...
Compare original and translation side by side
cloudflare-worker-basecloudflare-durable-objects@cloudflare/sandbox@0.6.3cloudflare/sandbox:0.6.3-pythoncloudflare/sandbox:<version>-pythoncloudflare-worker-basecloudflare-durable-objects@cloudflare/sandbox@0.6.3cloudflare/sandbox:0.6.3-pythoncloudflare/sandbox:<version>-pythonbun add @cloudflare/sandbox@latest # preferredbun add @cloudflare/sandbox@latest # 推荐方式
**wrangler.jsonc:**
```jsonc
{
"name": "my-sandbox-worker",
"main": "src/index.ts",
"compatibility_flags": ["nodejs_compat"],
"containers": [{
"class_name": "Sandbox",
"image": "cloudflare/sandbox:0.6.3-python",
"instance_type": "lite"
}],
"durable_objects": {
"bindings": [{
"class_name": "Sandbox",
"name": "Sandbox"
}]
},
"migrations": [{
"tag": "v1",
"new_sqlite_classes": ["Sandbox"]
}]
}nodejs_compatcontainersdurable_objectsmigrations
**wrangler.jsonc:**
```jsonc
{
"name": "my-sandbox-worker",
"main": "src/index.ts",
"compatibility_flags": ["nodejs_compat"],
"containers": [{
"class_name": "Sandbox",
"image": "cloudflare/sandbox:0.6.3-python",
"instance_type": "lite"
}],
"durable_objects": {
"bindings": [{
"class_name": "Sandbox",
"name": "Sandbox"
}]
},
"migrations": [{
"tag": "v1",
"new_sqlite_classes": ["Sandbox"]
}]
}nodejs_compatcontainersdurable_objectsmigrationsimport { getSandbox, type Sandbox } from '@cloudflare/sandbox';
export { Sandbox } from '@cloudflare/sandbox';
type Env = {
Sandbox: DurableObjectNamespace<Sandbox>;
};
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// Get sandbox instance (creates if doesn't exist)
const sandbox = getSandbox(env.Sandbox, 'my-first-sandbox');
// Execute Python code
const result = await sandbox.exec('python3 -c "print(2 + 2)"');
return Response.json({
output: result.stdout,
success: result.success,
exitCode: result.exitCode
});
}
};{ Sandbox }@cloudflare/sandboximport { getSandbox, type Sandbox } from '@cloudflare/sandbox';
export { Sandbox } from '@cloudflare/sandbox';
type Env = {
Sandbox: DurableObjectNamespace<Sandbox>;
};
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// 获取沙箱实例(不存在则创建)
const sandbox = getSandbox(env.Sandbox, 'my-first-sandbox');
// 执行Python代码
const result = await sandbox.exec('python3 -c "print(2 + 2)"');
return Response.json({
output: result.stdout,
success: result.success,
exitCode: result.exitCode
});
}
};{ Sandbox }@cloudflare/sandboxnpm run deploy
curl https://your-worker.workers.dev{
"output": "4\n",
"success": true,
"exitCode": 0
}npm run deploy
curl https://your-worker.workers.dev{
"output": "4\n",
"success": true,
"exitCode": 0
}npm config set ignore-scripts truesocket package score npm <pkg>socket npm install <pkg>dependency-upgradenpm config set ignore-scripts truesocket package score npm <pkg>socket npm install <pkg>dependency-upgrade┌─────────────────────────────────────────┐
│ Your Worker (Layer 1) │
│ - Handles HTTP requests │
│ - Calls getSandbox() │
│ - Uses sandbox.exec(), writeFile(), etc│
└──────────────┬──────────────────────────┘
│ RPC via Durable Object
┌──────────────▼──────────────────────────┐
│ Durable Object (Layer 2) │
│ - Routes by sandbox ID │
│ - Maintains persistent identity │
│ - Geographic stickiness │
└──────────────┬──────────────────────────┘
│ Container API
┌──────────────▼──────────────────────────┐
│ Ubuntu Container (Layer 3) │
│ - Full Linux environment │
│ - Python 3.11, Node 20, Git, etc. │
│ - Filesystem: /workspace, /tmp, /home │
│ - Process isolation (VM-based) │
└─────────────────────────────────────────┘┌─────────────────────────────────────────┐
│ 你的Worker(第一层) │
│ - 处理HTTP请求 │
│ - 调用getSandbox() │
│ - 使用sandbox.exec()、writeFile()等方法│
└──────────────┬──────────────────────────┘
│ 通过Durable Object进行RPC调用
┌──────────────▼──────────────────────────┐
│ Durable Object(第二层) │
│ - 按沙箱ID路由请求 │
│ - 维护持久化身份标识 │
│ - 地理位置粘性 │
└──────────────┬──────────────────────────┘
│ 容器API
┌──────────────▼──────────────────────────┐
│ Ubuntu容器(第三层) │
│ - 完整Linux环境 │
│ - 包含Python 3.11、Node 20、Git等工具 │
│ - 文件系统:/workspace、/tmp、/home │
│ - 基于VM的进程隔离 │
└─────────────────────────────────────────┘┌─────────┐ First request ┌────────┐ ~10 min idle ┌──────┐
│ Not │ ───────────────>│ Active │ ─────────────> │ Idle │
│ Created │ │ │ │ │
└─────────┘ └───┬────┘ └──┬───┘
│ ^ │
│ │ New request │
│ └──────────────────────┘
│ │
▼ ▼
Files persist ALL FILES DELETED
Processes run ALL PROCESSES KILLED
State maintained ALL STATE RESET┌─────────┐ 首次请求 ┌────────┐ 闲置约10分钟 ┌──────┐
│ 未创建 │ ───────────>│ 活跃 │ ─────────────> │ 闲置 │
│ │ │ │ │ │
└─────────┘ └───┬────┘ └──┬───┘
│ ^ │
│ │ 新请求 │
│ └──────────────────────┘
│ │
▼ ▼
文件持久化 所有文件被删除
进程持续运行 所有进程被终止
状态保持不变 所有状态重置/workspace/tmp/home/workspace/tmp/home// Save to R2 before container goes idle
await sandbox.writeFile('/workspace/data.txt', content);
const fileData = await sandbox.readFile('/workspace/data.txt');
await env.R2.put('backup/data.txt', fileData);
// Restore on next request
const restored = await env.R2.get('backup/data.txt');
if (restored) {
await sandbox.writeFile('/workspace/data.txt', await restored.text());
}// Check if setup needed (handles cold starts)
const exists = await sandbox.readdir('/workspace/project').catch(() => null);
if (!exists) {
await sandbox.gitCheckout(repoUrl, '/workspace/project');
await sandbox.exec('npm install', { cwd: '/workspace/project' });
}
// Now safe to run build
await sandbox.exec('npm run build', { cwd: '/workspace/project' });// 容器闲置前保存到R2
await sandbox.writeFile('/workspace/data.txt', content);
const fileData = await sandbox.readFile('/workspace/data.txt');
await env.R2.put('backup/data.txt', fileData);
// 下一次请求时恢复
const restored = await env.R2.get('backup/data.txt');
if (restored) {
await sandbox.writeFile('/workspace/data.txt', await restored.text());
}// 检查是否需要初始化(处理冷启动)
const exists = await sandbox.readdir('/workspace/project').catch(() => null);
if (!exists) {
await sandbox.gitCheckout(repoUrl, '/workspace/project');
await sandbox.exec('npm install', { cwd: '/workspace/project' });
}
// 现在可以安全执行构建
await sandbox.exec('npm run build', { cwd: '/workspace/project' });type ConversationState = {
sandboxId: string;
sessionId: string;
};
// First message: Create sandbox and session
const sandboxId = `user-${userId}`;
const sandbox = getSandbox(env.Sandbox, sandboxId);
const sessionId = await sandbox.createSession();
// Store in conversation state (database, KV, etc.)
await env.KV.put(`conversation:${conversationId}`, JSON.stringify({
sandboxId,
sessionId
}));
// Later messages: Reuse same session
const state = await env.KV.get(`conversation:${conversationId}`);
const { sandboxId, sessionId } = JSON.parse(state);
const sandbox = getSandbox(env.Sandbox, sandboxId);
// Commands run in same context
await sandbox.exec('cd /workspace/project', { session: sessionId });
await sandbox.exec('ls -la', { session: sessionId }); // Still in /workspace/project
await sandbox.exec('git status', { session: sessionId }); // Still in /workspace/projecttype ConversationState = {
sandboxId: string;
sessionId: string;
};
// 第一条消息:创建沙箱和会话
const sandboxId = `user-${userId}`;
const sandbox = getSandbox(env.Sandbox, sandboxId);
const sessionId = await sandbox.createSession();
// 存储到对话状态(数据库、KV等)
await env.KV.put(`conversation:${conversationId}`, JSON.stringify({
sandboxId,
sessionId
}));
// 后续消息:复用同一会话
const state = await env.KV.get(`conversation:${conversationId}`);
const { sandboxId, sessionId } = JSON.parse(state);
const sandbox = getSandbox(env.Sandbox, sandboxId);
// 命令在同一上下文执行
await sandbox.exec('cd /workspace/project', { session: sessionId });
await sandbox.exec('ls -la', { session: sessionId }); // 仍处于/workspace/project目录
await sandbox.exec('git status', { session: sessionId }); // 仍处于/workspace/project目录// ❌ WRONG: Each command runs in separate session
await sandbox.exec('cd /workspace/project');
await sandbox.exec('ls'); // NOT in /workspace/project (different session)// ❌ 错误:每个命令在独立会话中执行
await sandbox.exec('cd /workspace/project');
await sandbox.exec('ls'); // 不在/workspace/project目录(不同会话)const session1 = await sandbox.createSession();
const session2 = await sandbox.createSession();
// Run different tasks simultaneously
await Promise.all([
sandbox.exec('python train_model.py', { session: session1 }),
sandbox.exec('node generate_reports.js', { session: session2 })
]);const session1 = await sandbox.createSession();
const session2 = await sandbox.createSession();
// 同时运行不同任务
await Promise.all([
sandbox.exec('python train_model.py', { session: session1 }),
sandbox.exec('node generate_reports.js', { session: session2 })
]);const sandbox = getSandbox(env.Sandbox, `user-${userId}`);const sandbox = getSandbox(env.Sandbox, `user-${userId}`);const sandboxId = `session-${Date.now()}-${crypto.randomUUID()}`;
const sandbox = getSandbox(env.Sandbox, sandboxId);
// Always destroy after use
await sandbox.destroy();const sandboxId = `session-${Date.now()}-${crypto.randomUUID()}`;
const sandbox = getSandbox(env.Sandbox, sandboxId);
// 使用后务必销毁
await sandbox.destroy();const sandbox = getSandbox(env.Sandbox, `build-${repoName}-${commitSha}`);const sandbox = getSandbox(env.Sandbox, `build-${repoName}-${commitSha}`);references/api-reference.mdreferences/api-reference.mdif (!result.success) { handle error }export { Sandbox } from '@cloudflare/sandbox'if (!result.success) { 处理错误 }export { Sandbox } from '@cloudflare/sandbox'result.successresult.exitCodecd /dirlsresult.successresult.exitCodecd /dirlsReferenceError: fetch is not definedBuffer is not defined"compatibility_flags": ["nodejs_compat"]ReferenceError: fetch is not definedBuffer is not defined"compatibility_flags": ["nodejs_compat"]Error: Class 'Sandbox' not foundError: Class 'Sandbox' not foundcreateSession()createSession()result.successresult.exitCodeif (!result.success) throw new Error(result.stderr)result.successresult.exitCodeif (!result.success) throw new Error(result.stderr)Failed to build containernpm run devFailed to build containernpm run dev@cloudflare/sandboxcloudflare/sandbox@cloudflare/sandboxcloudflare/sandboxawait sandbox.destroy()await sandbox.destroy()exec()exec(){
"name": "my-sandbox-app",
"main": "src/index.ts",
"compatibility_date": "2025-10-29",
"compatibility_flags": ["nodejs_compat"], // ← REQUIRED
"containers": [{
"class_name": "Sandbox",
"image": "cloudflare/sandbox:0.6.3-python", // ← Use -python for Python support
"instance_type": "lite"
}],
"durable_objects": {
"bindings": [{"class_name": "Sandbox", "name": "Sandbox"}]
},
"migrations": [{
"tag": "v1",
"new_sqlite_classes": ["Sandbox"]
}]
}{
"name": "my-sandbox-app",
"main": "src/index.ts",
"compatibility_date": "2025-10-29",
"compatibility_flags": ["nodejs_compat"], // ← 必填
"containers": [{
"class_name": "Sandbox",
"image": "cloudflare/sandbox:0.6.3-python", // ← 需要Python支持请使用-python后缀
"instance_type": "lite"
}],
"durable_objects": {
"bindings": [{"class_name": "Sandbox", "name": "Sandbox"}]
},
"migrations": [{
"tag": "v1",
"new_sqlite_classes": ["Sandbox"]
}]
}references/patterns.mdreferences/patterns.mdsetup-sandbox-binding.shtest-sandbox.tsundefinedsetup-sandbox-binding.shtest-sandbox.tsundefinedundefinedundefinedreferences/persistence-guide.mdreferences/session-management.mdreferences/common-errors.mdreferences/naming-strategies.mdpersistence-guide.mdsession-management.mdcommon-errors.mdnaming-strategies.mdreferences/persistence-guide.mdreferences/session-management.mdreferences/common-errors.mdreferences/naming-strategies.mdpersistence-guide.mdsession-management.mdcommon-errors.mdnaming-strategies.mdreferences/advanced.mdreferences/advanced.md@cloudflare/sandbox@0.6.3cloudflare/sandbox:0.6.3-python@cloudflare/sandbox@0.6.3cloudflare/sandbox:0.6.3-python