Skip to content

Commit 47026f0

Browse files
Add process readiness documentation
Documents new waitForLog() and waitForPort() methods for detecting process readiness. Updates Commands API reference and Background Processes guide with practical examples. Related to cloudflare/sandbox-sdk#273 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 8ef2868 commit 47026f0

File tree

2 files changed

+144
-38
lines changed

2 files changed

+144
-38
lines changed

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

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ for await (const event of parseSSEStream<ExecEvent>(stream)) {
8787
Start a long-running background process.
8888

8989
```ts
90-
const process = await sandbox.startProcess(command: string, options?: ProcessOptions): Promise<ProcessInfo>
90+
const process = await sandbox.startProcess(command: string, options?: ProcessOptions): Promise<Process>
9191
```
9292

9393
**Parameters**:
@@ -96,7 +96,16 @@ const process = await sandbox.startProcess(command: string, options?: ProcessOpt
9696
- `cwd` - Working directory
9797
- `env` - Environment variables
9898

99-
**Returns**: `Promise<ProcessInfo>` with `id`, `pid`, `command`, `status`
99+
**Returns**: `Promise<Process>` object with properties and methods:
100+
- `id` - Unique process identifier
101+
- `pid` - System process ID
102+
- `command` - Command that was executed
103+
- `status` - Current process status
104+
- `kill(signal?: string)` - Terminate the process
105+
- `getStatus()` - Get current process status
106+
- `getLogs()` - Get accumulated logs
107+
- `waitForLog(pattern, timeout?)` - Wait for log pattern (see [process.waitForLog()](#processwaitforlog))
108+
- `waitForPort(port, options?)` - Wait for port readiness (see [process.waitForPort()](#processwaitforport))
100109

101110
<TypeScriptExample>
102111
```
@@ -213,6 +222,95 @@ console.log('Server logs:', logs);
213222
```
214223
</TypeScriptExample>
215224

225+
### `process.waitForLog()`
226+
227+
Wait for a log pattern to appear in process output. This method checks existing logs first, then streams new output until the pattern is found.
228+
229+
```ts
230+
const result = await process.waitForLog(pattern: string | RegExp, timeout?: number): Promise<WaitForLogResult>
231+
```
232+
233+
**Parameters**:
234+
- `pattern` - String to search for or RegExp pattern to match
235+
- `timeout` (optional) - Maximum time to wait in milliseconds (no timeout by default)
236+
237+
**Returns**: `Promise<WaitForLogResult>` with:
238+
- `line` - The log line that matched the pattern
239+
- `match` (optional) - RegExp capture groups if pattern was a RegExp
240+
241+
**Errors**:
242+
- `ProcessReadyTimeoutError` - Pattern not found within timeout period
243+
- `ProcessExitedBeforeReadyError` - Process exited before pattern appeared
244+
245+
<TypeScriptExample>
246+
```
247+
// Wait for simple string pattern
248+
const server = await sandbox.startProcess('python -m http.server 8000');
249+
await server.waitForLog('Serving HTTP');
250+
console.log('Server is ready');
251+
252+
// Wait with timeout
253+
const app = await sandbox.startProcess('npm run dev');
254+
await app.waitForLog('Local: http://localhost:3000', 30000); // 30s timeout
255+
256+
// Use RegExp for pattern matching
257+
const build = await sandbox.startProcess('npm run build');
258+
const result = await build.waitForLog(/Built in (\d+)ms/);
259+
console.log('Matched line:', result.line);
260+
console.log('Build time:', result.match?.[1]);
261+
```
262+
</TypeScriptExample>
263+
264+
### `process.waitForPort()`
265+
266+
Wait for a process to start listening on a port. Supports both HTTP health checks and TCP connection checks.
267+
268+
```ts
269+
await process.waitForPort(port: number, options?: WaitForPortOptions): Promise<void>
270+
```
271+
272+
**Parameters**:
273+
- `port` - Port number to check
274+
- `options` (optional):
275+
- `mode` - Check mode: `'http'` (default) or `'tcp'`
276+
- `path` - HTTP path to check (default: `'/'`, only for HTTP mode)
277+
- `status` - Expected HTTP status code or range (default: `{ min: 200, max: 399 }`)
278+
- Single number: exact match (e.g., `200`)
279+
- Object with min/max: range match (e.g., `{ min: 200, max: 299 }`)
280+
- `timeout` - Maximum time to wait in milliseconds (no timeout by default)
281+
- `interval` - Interval between checks in milliseconds (default: `500`)
282+
283+
**Errors**:
284+
- `ProcessReadyTimeoutError` - Port not ready within timeout period
285+
- `ProcessExitedBeforeReadyError` - Process exited before port became ready
286+
287+
<TypeScriptExample>
288+
```
289+
// Wait for HTTP endpoint with default settings (200-399 status on /)
290+
const web = await sandbox.startProcess('npm run dev');
291+
await web.waitForPort(3000);
292+
console.log('Web server ready at http://localhost:3000');
293+
294+
// Check specific health endpoint
295+
const api = await sandbox.startProcess('node api.js');
296+
await api.waitForPort(8080, {
297+
path: '/health',
298+
status: 200,
299+
timeout: 30000 // 30 second timeout
300+
});
301+
302+
// TCP-only check (just verify port accepts connections)
303+
const db = await sandbox.startProcess('redis-server');
304+
await db.waitForPort(6379, { mode: 'tcp' });
305+
306+
// Wait for specific status code range
307+
const app = await sandbox.startProcess('python app.py');
308+
await app.waitForPort(5000, {
309+
status: { min: 200, max: 299 } // Only 2xx status codes
310+
});
311+
```
312+
</TypeScriptExample>
313+
216314
## Related resources
217315

218316
- [Background processes guide](/sandbox/guides/background-processes/) - Managing long-running processes

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

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -83,36 +83,55 @@ const isRunning = processes.some(p => p.id === processId && p.status === 'runnin
8383
```
8484
</TypeScriptExample>
8585

86-
## Monitor process logs
86+
## Wait for process readiness
8787

88-
Stream logs in real-time to detect when a service is ready:
88+
Use `waitForPort()` or `waitForLog()` to wait for a process to become ready before proceeding:
8989

9090
<TypeScriptExample>
9191
```
92-
import { parseSSEStream, type LogEvent } from '@cloudflare/sandbox';
93-
92+
// Wait for HTTP server to be ready
9493
const server = await sandbox.startProcess('node server.js');
94+
await server.waitForPort(3000);
95+
console.log('Server is ready at http://localhost:3000');
96+
97+
// Wait for log pattern
98+
const app = await sandbox.startProcess('npm run dev');
99+
await app.waitForLog('Server listening');
100+
console.log('App is ready');
101+
102+
// Wait with timeout and custom health check
103+
const api = await sandbox.startProcess('python api.py');
104+
await api.waitForPort(8080, {
105+
path: '/health',
106+
timeout: 30000 // 30 seconds
107+
});
108+
```
109+
</TypeScriptExample>
95110

96-
// Stream logs
97-
const logStream = await sandbox.streamProcessLogs(server.id);
111+
## Monitor process logs
98112

99-
for await (const log of parseSSEStream<LogEvent>(logStream)) {
100-
console.log(log.data);
113+
Get accumulated logs from a running or completed process:
101114

102-
if (log.data.includes('Server listening')) {
103-
console.log('Server is ready!');
104-
break;
105-
}
106-
}
115+
<TypeScriptExample>
116+
```
117+
const logs = await server.getLogs();
118+
console.log('stdout:', logs.stdout);
119+
console.log('stderr:', logs.stderr);
107120
```
108121
</TypeScriptExample>
109122

110-
Or get accumulated logs:
123+
Or stream logs in real-time:
111124

112125
<TypeScriptExample>
113126
```
114-
const logs = await sandbox.getProcessLogs(server.id);
115-
console.log('Logs:', logs);
127+
import { parseSSEStream, type LogEvent } from '@cloudflare/sandbox';
128+
129+
const server = await sandbox.startProcess('node server.js');
130+
const logStream = await sandbox.streamProcessLogs(server.id);
131+
132+
for await (const log of parseSSEStream<LogEvent>(logStream)) {
133+
console.log(log.data);
134+
}
116135
```
117136
</TypeScriptExample>
118137

@@ -137,24 +156,20 @@ Start services in sequence, waiting for dependencies:
137156

138157
<TypeScriptExample>
139158
```
140-
import { parseSSEStream, type LogEvent } from '@cloudflare/sandbox';
141-
142159
// Start database first
143160
const db = await sandbox.startProcess('redis-server');
144161
145162
// Wait for database to be ready
146-
const dbLogs = await sandbox.streamProcessLogs(db.id);
147-
for await (const log of parseSSEStream<LogEvent>(dbLogs)) {
148-
if (log.data.includes('Ready to accept connections')) {
149-
break;
150-
}
151-
}
163+
await db.waitForPort(6379, { mode: 'tcp' });
152164
153165
// Now start API server (depends on database)
154166
const api = await sandbox.startProcess('node api-server.js', {
155167
env: { DATABASE_URL: 'redis://localhost:6379' }
156168
});
157169
170+
// Wait for API to be ready
171+
await api.waitForPort(8080, { path: '/health' });
172+
158173
console.log('All services running');
159174
```
160175
</TypeScriptExample>
@@ -165,7 +180,7 @@ By default, containers automatically shut down after 10 minutes of inactivity. F
165180

166181
<TypeScriptExample>
167182
```ts
168-
import { getSandbox, parseSSEStream, type LogEvent } from '@cloudflare/sandbox';
183+
import { getSandbox } from '@cloudflare/sandbox';
169184

170185
export { Sandbox } from '@cloudflare/sandbox';
171186

@@ -180,16 +195,8 @@ export default {
180195
// Start a long-running build process
181196
const build = await sandbox.startProcess('npm run build:production');
182197

183-
// Monitor progress
184-
const logs = await sandbox.streamProcessLogs(build.id);
185-
186-
// Process can run indefinitely without container shutdown
187-
for await (const log of parseSSEStream<LogEvent>(logs)) {
188-
console.log(log.data);
189-
if (log.data.includes('Build complete')) {
190-
break;
191-
}
192-
}
198+
// Wait for completion
199+
await build.waitForLog('Build complete', 600000); // 10 minute timeout
193200

194201
return new Response('Build completed');
195202
} finally {
@@ -207,7 +214,8 @@ When using `keepAlive: true`, containers will not automatically timeout. You **m
207214

208215
## Best practices
209216

210-
- **Wait for readiness** - Stream logs to detect when services are ready
217+
- **Wait for readiness** - Use `waitForPort()` or `waitForLog()` to detect when services are ready
218+
- **Set timeouts** - Always specify timeout values to prevent indefinite waiting
211219
- **Clean up** - Always stop processes when done
212220
- **Handle failures** - Monitor logs for errors and restart if needed
213221
- **Use try/finally** - Ensure cleanup happens even on errors

0 commit comments

Comments
 (0)