Skip to content

Commit 5a3a97b

Browse files
committed
add docs for keepAlive flag
1 parent 313d562 commit 5a3a97b

File tree

3 files changed

+121
-32
lines changed

3 files changed

+121
-32
lines changed

src/content/docs/sandbox/api/sessions.mdx

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,44 @@ Create isolated execution contexts within a sandbox. Each session maintains its
1313
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.
1414
:::
1515

16+
## Sandbox options
17+
18+
When creating a sandbox with `getSandbox()`, you can configure its lifecycle behavior:
19+
20+
```ts
21+
import { getSandbox } from '@cloudflare/sandbox';
22+
23+
const sandbox = getSandbox(binding, sandboxId, options?: SandboxOptions);
24+
```
25+
26+
**Available options**:
27+
28+
- `keepAlive` (boolean) - Keep the container alive indefinitely by preventing automatic shutdown. When `true`, the container will never auto-timeout and must be explicitly destroyed using `destroy()`. Default: `false`
29+
30+
<TypeScriptExample>
31+
```
32+
// For long-running processes that need the container to stay alive
33+
const sandbox = getSandbox(env.Sandbox, 'user-123', {
34+
keepAlive: true
35+
});
36+
37+
// Run your long-running process
38+
await sandbox.startProcess('python long_running_script.py');
39+
40+
// Important: Must explicitly destroy when done
41+
try {
42+
// Your work here
43+
} finally {
44+
await sandbox.destroy(); // Required to prevent resource leaks
45+
}
46+
47+
````
48+
</TypeScriptExample>
49+
50+
:::caution[Resource management with keepAlive]
51+
When `keepAlive: true` is set, containers will not automatically timeout and must be explicitly destroyed using `destroy()` to prevent resource leaks and avoid counting toward account limits indefinitely.
52+
:::
53+
1654
## Methods
1755
1856
### `createSession()`
@@ -41,15 +79,15 @@ const prodSession = await sandbox.createSession({
4179
});
4280
4381
const testSession = await sandbox.createSession({
44-
id: 'test',
45-
env: { NODE_ENV: 'test', API_URL: 'http://localhost:3000' },
46-
cwd: '/workspace/test'
82+
id: 'test',
83+
env: { NODE_ENV: 'test', API_URL: 'http://localhost:3000' },
84+
cwd: '/workspace/test'
4785
});
4886
4987
// Run in parallel
5088
const [prodResult, testResult] = await Promise.all([
51-
prodSession.exec('npm run build'),
52-
testSession.exec('npm run build')
89+
prodSession.exec('npm run build'),
90+
testSession.exec('npm run build')
5391
]);
5492
```
5593
</TypeScriptExample>
@@ -101,9 +139,9 @@ const sandbox = getSandbox(env.Sandbox, 'user-123');
101139
102140
// Set environment variables first
103141
await sandbox.setEnvVars({
104-
API_KEY: env.OPENAI_API_KEY,
105-
DATABASE_URL: env.DATABASE_URL,
106-
NODE_ENV: 'production'
142+
API_KEY: env.OPENAI_API_KEY,
143+
DATABASE_URL: env.DATABASE_URL,
144+
NODE_ENV: 'production'
107145
});
108146
109147
// Now commands can access these variables
@@ -120,21 +158,23 @@ await sandbox.destroy(): Promise<void>
120158
```
121159

122160
:::note
123-
Containers automatically sleep after 3 minutes of inactivity, but still count toward account limits. Use `destroy()` to immediately free up resources.
161+
Containers automatically sleep after 10 minutes of inactivity, but still count toward account limits. Use `destroy()` to immediately free up resources.
162+
163+
**Important**: When using `keepAlive: true`, containers will not automatically timeout, so calling `destroy()` is **required** to prevent resource leaks.
124164
:::
125165

126166
<TypeScriptExample>
127167
```
128168
async function executeCode(code: string): Promise<string> {
129169
const sandbox = getSandbox(env.Sandbox, `temp-${Date.now()}`);
130170
131-
try {
132-
await sandbox.writeFile('/tmp/code.py', code);
133-
const result = await sandbox.exec('python /tmp/code.py');
134-
return result.stdout;
135-
} finally {
136-
await sandbox.destroy();
137-
}
171+
try {
172+
await sandbox.writeFile('/tmp/code.py', code);
173+
const result = await sandbox.exec('python /tmp/code.py');
174+
return result.stdout;
175+
} finally {
176+
await sandbox.destroy();
177+
}
138178
}
139179
```
140180
</TypeScriptExample>
@@ -143,13 +183,15 @@ async function executeCode(code: string): Promise<string> {
143183

144184
The `ExecutionSession` object has all sandbox methods bound to the specific session:
145185

146-
**Commands**: [`exec()`](/sandbox/api/commands/#exec), [`execStream()`](/sandbox/api/commands/#execstream)
147-
**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)
148-
**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)
149-
**Environment**: [`setEnvVars()`](/sandbox/api/sessions/#setenvvars)
186+
**Commands**: [`exec()`](/sandbox/api/commands/#exec), [`execStream()`](/sandbox/api/commands/#execstream)
187+
**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)
188+
**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)
189+
**Environment**: [`setEnvVars()`](/sandbox/api/sessions/#setenvvars)
150190
**Code Interpreter**: [`createCodeContext()`](/sandbox/api/interpreter/#createcodecontext), [`runCode()`](/sandbox/api/interpreter/#runcode), [`listCodeContexts()`](/sandbox/api/interpreter/#listcodecontexts), [`deleteCodeContext()`](/sandbox/api/interpreter/#deletecodecontext)
151191

152192
## Related resources
153193

154194
- [Session management concept](/sandbox/concepts/sessions/) - How sessions work
155195
- [Commands API](/sandbox/api/commands/) - Execute commands
196+
```
197+
````

src/content/docs/sandbox/concepts/sandboxes.mdx

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,17 @@ A sandbox is an isolated execution environment where your code runs. Each sandbo
2020
A sandbox is created the first time you reference its ID:
2121

2222
```typescript
23-
const sandbox = getSandbox(env.Sandbox, 'user-123');
23+
const sandbox = getSandbox(env.Sandbox, "user-123");
2424
await sandbox.exec('echo "Hello"'); // First request creates sandbox
2525
```
2626

27-
**Duration**: 100-300ms (cold start) or \<10ms (if warm)
28-
2927
### Active
3028

3129
The sandbox container is running and processing requests. All state remains available: files, running processes, shell sessions, and environment variables.
3230

3331
### Idle
3432

35-
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.
33+
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.
3634

3735
### Destruction
3836

@@ -48,12 +46,14 @@ await sandbox.destroy();
4846
Sandbox state exists only while the container is active. Understanding this is critical for building reliable applications.
4947

5048
**While the container is active** (typically minutes to hours of activity):
49+
5150
- Files written to `/workspace`, `/tmp`, `/home` remain available
5251
- Background processes continue running
5352
- Shell sessions maintain their working directory and environment
5453
- Code interpreter contexts retain variables and imports
5554

5655
**When the container stops** (due to inactivity or explicit destruction):
56+
5757
- All files are deleted
5858
- All processes terminate
5959
- All shell state resets
@@ -95,6 +95,7 @@ Idempotent operations with clear task-to-sandbox mapping. Good for builds, pipel
9595
The first request to a sandbox determines its geographic location. Subsequent requests route to the same location.
9696

9797
**For global apps**:
98+
9899
- Option 1: Multiple sandboxes per user with region suffix (`user-123-us`, `user-123-eu`)
99100
- Option 2: Single sandbox per user (simpler, but some users see higher latency)
100101

@@ -104,10 +105,10 @@ The first request to a sandbox determines its geographic location. Subsequent re
104105

105106
```typescript
106107
try {
107-
const sandbox = getSandbox(env.Sandbox, sessionId);
108-
await sandbox.exec('npm run build');
108+
const sandbox = getSandbox(env.Sandbox, sessionId);
109+
await sandbox.exec("npm run build");
109110
} finally {
110-
await sandbox.destroy(); // Clean up temporary sandboxes
111+
await sandbox.destroy(); // Clean up temporary sandboxes
111112
}
112113
```
113114

@@ -121,13 +122,13 @@ Containers restart after inactivity or failures. Design your application to hand
121122

122123
```typescript
123124
// Check if required files exist before using them
124-
const files = await sandbox.listFiles('/workspace');
125-
if (!files.includes('data.json')) {
126-
// Reinitialize: container restarted and lost previous state
127-
await sandbox.writeFile('/workspace/data.json', initialData);
125+
const files = await sandbox.listFiles("/workspace");
126+
if (!files.includes("data.json")) {
127+
// Reinitialize: container restarted and lost previous state
128+
await sandbox.writeFile("/workspace/data.json", initialData);
128129
}
129130

130-
await sandbox.exec('python process.py');
131+
await sandbox.exec("python process.py");
131132
```
132133

133134
## Best practices

src/content/docs/sandbox/guides/background-processes.mdx

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,12 +159,57 @@ console.log('All services running');
159159
```
160160
</TypeScriptExample>
161161

162+
## Keep containers alive for long-running processes
163+
164+
By default, containers automatically shut down after 3 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:
165+
166+
<TypeScriptExample>
167+
```
168+
import { getSandbox, parseSSEStream, type LogEvent } from '@cloudflare/sandbox';
169+
170+
export default {
171+
async fetch(request: Request, env: Env): Promise<Response> {
172+
// Enable keepAlive for long-running processes
173+
const sandbox = getSandbox(env.Sandbox, 'build-job-123', {
174+
keepAlive: true
175+
});
176+
177+
try {
178+
// Start a long-running build process
179+
const build = await sandbox.startProcess('npm run build:production');
180+
181+
// Monitor progress
182+
const logs = await sandbox.streamProcessLogs(build.id);
183+
184+
// Process can run indefinitely without container shutdown
185+
for await (const log of parseSSEStream<LogEvent>(logs)) {
186+
console.log(log.data);
187+
if (log.data.includes('Build complete')) {
188+
break;
189+
}
190+
}
191+
192+
return new Response('Build completed');
193+
} finally {
194+
// Important: Must explicitly destroy when done
195+
await sandbox.destroy();
196+
}
197+
}
198+
};
199+
```
200+
</TypeScriptExample>
201+
202+
:::caution[Always destroy with keepAlive]
203+
When using `keepAlive: true`, containers will not automatically timeout. You **must** call `sandbox.destroy()` when finished to prevent resource leaks and avoid counting containers toward your account limits indefinitely.
204+
:::
205+
162206
## Best practices
163207

164208
- **Wait for readiness** - Stream logs to detect when services are ready
165209
- **Clean up** - Always stop processes when done
166210
- **Handle failures** - Monitor logs for errors and restart if needed
167211
- **Use try/finally** - Ensure cleanup happens even on errors
212+
- **Use keepAlive for long-running tasks** - Prevent container shutdown during processes with idle periods
168213

169214
## Troubleshooting
170215

@@ -199,6 +244,7 @@ const server = await sandbox.startProcess('node server.js');
199244
## Related resources
200245

201246
- [Commands API reference](/sandbox/api/commands/) - Complete process management API
247+
- [Sessions API reference](/sandbox/api/sessions/) - Container lifecycle and keepAlive option
202248
- [Execute commands guide](/sandbox/guides/execute-commands/) - One-time command execution
203249
- [Expose services guide](/sandbox/guides/expose-services/) - Make processes accessible
204250
- [Streaming output guide](/sandbox/guides/streaming-output/) - Monitor process output

0 commit comments

Comments
 (0)