diff --git a/src/content/docs/sandbox/api/sessions.mdx b/src/content/docs/sandbox/api/sessions.mdx index 90ff309d9693a6a..6b618cf346814cf 100644 --- a/src/content/docs/sandbox/api/sessions.mdx +++ b/src/content/docs/sandbox/api/sessions.mdx @@ -13,6 +13,10 @@ Create isolated execution contexts within a sandbox. Each session maintains its Every sandbox has a default session that automatically maintains shell state. Create additional sessions when you need isolated shell contexts for different environments or parallel workflows. ::: +:::note +For sandbox-level configuration options like `keepAlive`, refer to the [Sandbox options configuration](/sandbox/configuration/sandbox-options/). +::: + ## Methods ### `createSession()` @@ -120,7 +124,9 @@ await sandbox.destroy(): Promise ``` :::note -Containers automatically sleep after 3 minutes of inactivity, but still count toward account limits. Use `destroy()` to immediately free up resources. +Containers automatically sleep after 10 minutes of inactivity, but still count toward account limits. Use `destroy()` to immediately free up resources. + +**Important**: When using [`keepAlive: true`](/sandbox/configuration/sandbox-options/#keepalive), containers will not automatically timeout, so calling `destroy()` is **required** to prevent containers running indefinitely. ::: @@ -143,10 +149,10 @@ async function executeCode(code: string): Promise { The `ExecutionSession` object has all sandbox methods bound to the specific session: -**Commands**: [`exec()`](/sandbox/api/commands/#exec), [`execStream()`](/sandbox/api/commands/#execstream) -**Processes**: [`startProcess()`](/sandbox/api/commands/#startprocess), [`listProcesses()`](/sandbox/api/commands/#listprocesses), [`killProcess()`](/sandbox/api/commands/#killprocess), [`killAllProcesses()`](/sandbox/api/commands/#killallprocesses), [`getProcessLogs()`](/sandbox/api/commands/#getprocesslogs), [`streamProcessLogs()`](/sandbox/api/commands/#streamprocesslogs) -**Files**: [`writeFile()`](/sandbox/api/files/#writefile), [`readFile()`](/sandbox/api/files/#readfile), [`mkdir()`](/sandbox/api/files/#mkdir), [`deleteFile()`](/sandbox/api/files/#deletefile), [`renameFile()`](/sandbox/api/files/#renamefile), [`moveFile()`](/sandbox/api/files/#movefile), [`gitCheckout()`](/sandbox/api/files/#gitcheckout) -**Environment**: [`setEnvVars()`](/sandbox/api/sessions/#setenvvars) +**Commands**: [`exec()`](/sandbox/api/commands/#exec), [`execStream()`](/sandbox/api/commands/#execstream) +**Processes**: [`startProcess()`](/sandbox/api/commands/#startprocess), [`listProcesses()`](/sandbox/api/commands/#listprocesses), [`killProcess()`](/sandbox/api/commands/#killprocess), [`killAllProcesses()`](/sandbox/api/commands/#killallprocesses), [`getProcessLogs()`](/sandbox/api/commands/#getprocesslogs), [`streamProcessLogs()`](/sandbox/api/commands/#streamprocesslogs) +**Files**: [`writeFile()`](/sandbox/api/files/#writefile), [`readFile()`](/sandbox/api/files/#readfile), [`mkdir()`](/sandbox/api/files/#mkdir), [`deleteFile()`](/sandbox/api/files/#deletefile), [`renameFile()`](/sandbox/api/files/#renamefile), [`moveFile()`](/sandbox/api/files/#movefile), [`gitCheckout()`](/sandbox/api/files/#gitcheckout) +**Environment**: [`setEnvVars()`](/sandbox/api/sessions/#setenvvars) **Code Interpreter**: [`createCodeContext()`](/sandbox/api/interpreter/#createcodecontext), [`runCode()`](/sandbox/api/interpreter/#runcode), [`listCodeContexts()`](/sandbox/api/interpreter/#listcodecontexts), [`deleteCodeContext()`](/sandbox/api/interpreter/#deletecodecontext) ## Related resources diff --git a/src/content/docs/sandbox/concepts/sandboxes.mdx b/src/content/docs/sandbox/concepts/sandboxes.mdx index 98f04840e085835..b68c8f3fd2d7bd6 100644 --- a/src/content/docs/sandbox/concepts/sandboxes.mdx +++ b/src/content/docs/sandbox/concepts/sandboxes.mdx @@ -20,19 +20,17 @@ A sandbox is an isolated execution environment where your code runs. Each sandbo A sandbox is created the first time you reference its ID: ```typescript -const sandbox = getSandbox(env.Sandbox, 'user-123'); +const sandbox = getSandbox(env.Sandbox, "user-123"); await sandbox.exec('echo "Hello"'); // First request creates sandbox ``` -**Duration**: 100-300ms (cold start) or \<10ms (if warm) - ### Active The sandbox container is running and processing requests. All state remains available: files, running processes, shell sessions, and environment variables. ### Idle -After a period of inactivity, the container stops to free resources. When the next request arrives, a fresh container starts. All previous state is lost and the environment resets to its initial state. +After a period of inactivity (10 minutes by default), the container stops to free resources. When the next request arrives, a fresh container starts. All previous state is lost and the environment resets to its initial state. ### Destruction @@ -48,12 +46,14 @@ await sandbox.destroy(); Sandbox state exists only while the container is active. Understanding this is critical for building reliable applications. **While the container is active** (typically minutes to hours of activity): + - Files written to `/workspace`, `/tmp`, `/home` remain available - Background processes continue running - Shell sessions maintain their working directory and environment - Code interpreter contexts retain variables and imports **When the container stops** (due to inactivity or explicit destruction): + - All files are deleted - All processes terminate - All shell state resets @@ -95,6 +95,7 @@ Idempotent operations with clear task-to-sandbox mapping. Good for builds, pipel The first request to a sandbox determines its geographic location. Subsequent requests route to the same location. **For global apps**: + - Option 1: Multiple sandboxes per user with region suffix (`user-123-us`, `user-123-eu`) - Option 2: Single sandbox per user (simpler, but some users see higher latency) @@ -104,10 +105,10 @@ The first request to a sandbox determines its geographic location. Subsequent re ```typescript try { - const sandbox = getSandbox(env.Sandbox, sessionId); - await sandbox.exec('npm run build'); + const sandbox = getSandbox(env.Sandbox, sessionId); + await sandbox.exec("npm run build"); } finally { - await sandbox.destroy(); // Clean up temporary sandboxes + await sandbox.destroy(); // Clean up temporary sandboxes } ``` @@ -121,13 +122,13 @@ Containers restart after inactivity or failures. Design your application to hand ```typescript // Check if required files exist before using them -const files = await sandbox.listFiles('/workspace'); -if (!files.includes('data.json')) { - // Reinitialize: container restarted and lost previous state - await sandbox.writeFile('/workspace/data.json', initialData); +const files = await sandbox.listFiles("/workspace"); +if (!files.includes("data.json")) { + // Reinitialize: container restarted and lost previous state + await sandbox.writeFile("/workspace/data.json", initialData); } -await sandbox.exec('python process.py'); +await sandbox.exec("python process.py"); ``` ## Best practices diff --git a/src/content/docs/sandbox/configuration/index.mdx b/src/content/docs/sandbox/configuration/index.mdx index 4b064e8a701cea4..3022431a441a499 100644 --- a/src/content/docs/sandbox/configuration/index.mdx +++ b/src/content/docs/sandbox/configuration/index.mdx @@ -37,6 +37,14 @@ Configure your Sandbox SDK deployment with Wrangler, customize container images, Pass configuration and secrets to your sandboxes using environment variables. + + Configure sandbox behavior with options like `keepAlive` for long-running processes. + + ## Related resources diff --git a/src/content/docs/sandbox/configuration/sandbox-options.mdx b/src/content/docs/sandbox/configuration/sandbox-options.mdx new file mode 100644 index 000000000000000..7df842e7dde9b8b --- /dev/null +++ b/src/content/docs/sandbox/configuration/sandbox-options.mdx @@ -0,0 +1,65 @@ +--- +title: Sandbox options +pcx_content_type: configuration +sidebar: + order: 4 +--- + +import { TypeScriptExample } from "~/components"; + +Configure sandbox behavior by passing options when creating a sandbox instance with `getSandbox()`. + +## Available options + +```ts +import { getSandbox } from '@cloudflare/sandbox'; + +const sandbox = getSandbox(binding, sandboxId, options?: SandboxOptions); +``` + +### keepAlive + +**Type**: `boolean` +**Default**: `false` + +Keep the container alive indefinitely by preventing automatic shutdown. When `true`, the container will never auto-timeout and must be explicitly destroyed using `destroy()`. + + +```ts +// For long-running processes that need the container to stay alive +const sandbox = getSandbox(env.Sandbox, 'user-123', { + keepAlive: true +}); + +// Run your long-running process +await sandbox.startProcess('python long_running_script.py'); + +// Important: Must explicitly destroy when done +try { + // Your work here +} finally { + await sandbox.destroy(); // Required to prevent containers running indefinitely +} +``` + + +:::caution[Resource management with keepAlive] +When `keepAlive: true` is set, containers will not automatically timeout. They must be explicitly destroyed using `destroy()` to prevent containers running indefinitely and counting toward your account limits. +::: + +## When to use keepAlive + +Use `keepAlive: true` for: + +- **Long-running builds** - CI/CD pipelines that may have idle periods between steps +- **Batch processing** - Jobs that process data in waves with gaps between batches +- **Monitoring tasks** - Processes that periodically check external services +- **Interactive sessions** - User-driven workflows where the container should remain available + +By default, containers automatically shut down after 10 minutes of inactivity. The `keepAlive` option prevents this automatic shutdown. + +## Related resources + +- [Background processes guide](/sandbox/guides/background-processes/) - Using `keepAlive` with long-running processes +- [Sessions API reference](/sandbox/api/sessions/) - Container lifecycle management +- [Sandboxes concept](/sandbox/concepts/sandboxes/) - Understanding sandbox lifecycle diff --git a/src/content/docs/sandbox/guides/background-processes.mdx b/src/content/docs/sandbox/guides/background-processes.mdx index c9d48b30ef96c2f..4d0a2dac0eb6da1 100644 --- a/src/content/docs/sandbox/guides/background-processes.mdx +++ b/src/content/docs/sandbox/guides/background-processes.mdx @@ -159,12 +159,57 @@ console.log('All services running'); ``` +## Keep containers alive for long-running processes + +By default, containers automatically shut down after 10 minutes of inactivity. For long-running processes that may have idle periods (like CI/CD pipelines, batch jobs, or monitoring tasks), use the [`keepAlive` option](/sandbox/configuration/sandbox-options/#keepalive): + + +```ts +import { getSandbox, parseSSEStream, type LogEvent } from '@cloudflare/sandbox'; + +export default { + async fetch(request: Request, env: Env): Promise { + // Enable keepAlive for long-running processes + const sandbox = getSandbox(env.Sandbox, 'build-job-123', { + keepAlive: true + }); + + try { + // Start a long-running build process + const build = await sandbox.startProcess('npm run build:production'); + + // Monitor progress + const logs = await sandbox.streamProcessLogs(build.id); + + // Process can run indefinitely without container shutdown + for await (const log of parseSSEStream(logs)) { + console.log(log.data); + if (log.data.includes('Build complete')) { + break; + } + } + + return new Response('Build completed'); + } finally { + // Important: Must explicitly destroy when done + await sandbox.destroy(); + } + } +}; +``` + + +:::caution[Always destroy with keepAlive] +When using `keepAlive: true`, containers will not automatically timeout. You **must** call `sandbox.destroy()` when finished to prevent containers running indefinitely and counting toward your account limits. +::: + ## Best practices - **Wait for readiness** - Stream logs to detect when services are ready - **Clean up** - Always stop processes when done - **Handle failures** - Monitor logs for errors and restart if needed - **Use try/finally** - Ensure cleanup happens even on errors +- **Use `keepAlive` for long-running tasks** - Prevent container shutdown during processes with idle periods ## Troubleshooting @@ -199,6 +244,8 @@ const server = await sandbox.startProcess('node server.js'); ## Related resources - [Commands API reference](/sandbox/api/commands/) - Complete process management API +- [Sandbox options configuration](/sandbox/configuration/sandbox-options/) - Configure `keepAlive` and other options +- [Sessions API reference](/sandbox/api/sessions/) - Container lifecycle management - [Execute commands guide](/sandbox/guides/execute-commands/) - One-time command execution - [Expose services guide](/sandbox/guides/expose-services/) - Make processes accessible - [Streaming output guide](/sandbox/guides/streaming-output/) - Monitor process output