diff --git a/src/content/docs/sandbox/api/commands.mdx b/src/content/docs/sandbox/api/commands.mdx index 324dcbe5df5a311..c8aacaea1d39c00 100644 --- a/src/content/docs/sandbox/api/commands.mdx +++ b/src/content/docs/sandbox/api/commands.mdx @@ -87,7 +87,7 @@ for await (const event of parseSSEStream(stream)) { Start a long-running background process. ```ts -const process = await sandbox.startProcess(command: string, options?: ProcessOptions): Promise +const process = await sandbox.startProcess(command: string, options?: ProcessOptions): Promise ``` **Parameters**: @@ -96,7 +96,16 @@ const process = await sandbox.startProcess(command: string, options?: ProcessOpt - `cwd` - Working directory - `env` - Environment variables -**Returns**: `Promise` with `id`, `pid`, `command`, `status` +**Returns**: `Promise` object with: +- `id` - Unique process identifier +- `pid` - System process ID +- `command` - The command being executed +- `status` - Current status (`'running'`, `'exited'`, etc.) +- `kill()` - Stop the process +- `getStatus()` - Get current status +- `getLogs()` - Get accumulated logs +- `waitForPort()` - Wait for process to listen on a port +- `waitForLog()` - Wait for pattern in process output ``` @@ -213,6 +222,100 @@ console.log('Server logs:', logs); ``` +## Process readiness methods + +The `Process` object returned by `startProcess()` includes methods to wait for the process to be ready before proceeding. + +### `process.waitForPort()` + +Wait for a process to listen on a port. + +```ts +await process.waitForPort(port: number, options?: WaitForPortOptions): Promise +``` + +**Parameters**: +- `port` - The port number to check +- `options` (optional): + - `mode` - Check mode: `'http'` (default) or `'tcp'` + - `timeout` - Maximum wait time in milliseconds + - `interval` - Check interval in milliseconds (default: `100`) + - `path` - HTTP path to check (default: `'/'`, HTTP mode only) + - `status` - Expected HTTP status range (default: `{ min: 200, max: 399 }`, HTTP mode only) + +**HTTP mode** (default) makes an HTTP GET request and checks the response status: + + +``` +const server = await sandbox.startProcess('node server.js'); + +// Wait for server to be ready (HTTP mode) +await server.waitForPort(3000); + +// Check specific endpoint and status +await server.waitForPort(8080, { + path: '/health', + status: { min: 200, max: 299 }, + timeout: 30000 +}); +``` + + +**TCP mode** checks if the port accepts connections: + + +``` +const db = await sandbox.startProcess('redis-server'); + +// Wait for database to accept connections +await db.waitForPort(6379, { + mode: 'tcp', + timeout: 10000 +}); +``` + + +**Throws**: +- `ProcessReadyTimeoutError` - If port does not become ready within timeout +- `ProcessExitedBeforeReadyError` - If process exits before becoming ready + +### `process.waitForLog()` + +Wait for a pattern to appear in process output. + +```ts +const result = await process.waitForLog(pattern: string | RegExp, timeout?: number): Promise +``` + +**Parameters**: +- `pattern` - String or RegExp to match in stdout/stderr +- `timeout` - Maximum wait time in milliseconds (optional) + +**Returns**: `Promise` with: +- `line` - The matching line of output +- `matches` - Array of capture groups (for RegExp patterns) + + +``` +const server = await sandbox.startProcess('node server.js'); + +// Wait for string pattern +const result = await server.waitForLog('Server listening'); +console.log('Ready:', result.line); + +// Wait for RegExp with capture groups +const result = await server.waitForLog(/Server listening on port (\d+)/); +console.log('Port:', result.matches[1]); // Extracted port number + +// With timeout +await server.waitForLog('Ready', 30000); +``` + + +**Throws**: +- `ProcessReadyTimeoutError` - If pattern is not found within timeout +- `ProcessExitedBeforeReadyError` - If process exits before pattern appears + ## Related resources - [Background processes guide](/sandbox/guides/background-processes/) - Managing long-running processes diff --git a/src/content/docs/sandbox/guides/background-processes.mdx b/src/content/docs/sandbox/guides/background-processes.mdx index 229587d8106e971..a523eba829da408 100644 --- a/src/content/docs/sandbox/guides/background-processes.mdx +++ b/src/content/docs/sandbox/guides/background-processes.mdx @@ -83,9 +83,36 @@ const isRunning = processes.some(p => p.id === processId && p.status === 'runnin ``` +## Wait for process readiness + +Wait for a process to be ready before proceeding: + + +``` +const server = await sandbox.startProcess('node server.js'); + +// Wait for server to respond on port 3000 +await server.waitForPort(3000); + +console.log('Server is ready'); +``` + + +Or wait for specific log patterns: + + +``` +const server = await sandbox.startProcess('node server.js'); + +// Wait for log message +const result = await server.waitForLog('Server listening'); +console.log('Server is ready:', result.line); +``` + + ## Monitor process logs -Stream logs in real-time to detect when a service is ready: +Stream logs in real-time: ``` @@ -98,11 +125,6 @@ const logStream = await sandbox.streamProcessLogs(server.id); for await (const log of parseSSEStream(logStream)) { console.log(log.data); - - if (log.data.includes('Server listening')) { - console.log('Server is ready!'); - break; - } } ``` @@ -137,24 +159,20 @@ Start services in sequence, waiting for dependencies: ``` -import { parseSSEStream, type LogEvent } from '@cloudflare/sandbox'; - // Start database first const db = await sandbox.startProcess('redis-server'); // Wait for database to be ready -const dbLogs = await sandbox.streamProcessLogs(db.id); -for await (const log of parseSSEStream(dbLogs)) { - if (log.data.includes('Ready to accept connections')) { - break; - } -} +await db.waitForPort(6379, { mode: 'tcp' }); // Now start API server (depends on database) const api = await sandbox.startProcess('node api-server.js', { env: { DATABASE_URL: 'redis://localhost:6379' } }); +// Wait for API to be ready +await api.waitForPort(8080, { path: '/health' }); + console.log('All services running'); ``` @@ -207,7 +225,7 @@ When using `keepAlive: true`, containers will not automatically timeout. You **m ## Best practices -- **Wait for readiness** - Stream logs to detect when services are ready +- **Wait for readiness** - Use `waitForPort()` or `waitForLog()` 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