Skip to content

Commit ceaa95e

Browse files
Document process readiness feature
Adds documentation for waitForLog() and waitForPort() methods that allow waiting for processes to be ready before proceeding. Updates examples throughout the docs to use these new simpler patterns instead of manual delays or streaming logs. Changes: - API reference: Document waitForLog() and waitForPort() on Process interface - Background processes guide: Show new readiness methods as primary pattern - Expose services guide: Update all examples to use waitForPort() Synced from cloudflare/sandbox-sdk#273 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 50504a5 commit ceaa95e

File tree

3 files changed

+134
-49
lines changed

3 files changed

+134
-49
lines changed

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

Lines changed: 70 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,7 @@ 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>` with properties `id`, `pid`, `command`, `status` and methods `waitForLog()`, `waitForPort()`, `kill()`, `getStatus()`, `getLogs()`
100100

101101
<TypeScriptExample>
102102
```
@@ -111,6 +111,74 @@ const app = await sandbox.startProcess('node app.js', {
111111
```
112112
</TypeScriptExample>
113113

114+
## Process Readiness Methods
115+
116+
Methods available on the `Process` object returned by `startProcess()`.
117+
118+
### `waitForLog()`
119+
120+
Wait for a process to output a specific log message or pattern.
121+
122+
```ts
123+
const result = await process.waitForLog(pattern: string | RegExp, timeout?: number): Promise<WaitForLogResult>
124+
```
125+
126+
**Parameters**:
127+
- `pattern` - String to match or regular expression pattern
128+
- `timeout` - Maximum time to wait in milliseconds (default: 30000)
129+
130+
**Returns**: `Promise<WaitForLogResult>` with `line` (matched log line) and `match` (regex capture groups if pattern was RegExp)
131+
132+
**Throws**:
133+
- `ProcessReadyTimeoutError` - Pattern not found within timeout
134+
- `ProcessExitedBeforeReadyError` - Process exited before pattern appeared
135+
136+
<TypeScriptExample>
137+
```
138+
const proc = await sandbox.startProcess('npm start');
139+
140+
// Wait for string match
141+
await proc.waitForLog('Server listening on port 3000');
142+
143+
// Wait for regex pattern and extract values
144+
const result = await proc.waitForLog(/listening on port (\d+)/);
145+
console.log('Port:', result.match[1]); // Access captured group
146+
147+
// Custom timeout
148+
await proc.waitForLog('Database connected', 60000); // 60 seconds
149+
```
150+
</TypeScriptExample>
151+
152+
### `waitForPort()`
153+
154+
Wait for a process to start accepting connections on a specific port.
155+
156+
```ts
157+
await process.waitForPort(port: number, timeout?: number): Promise<void>
158+
```
159+
160+
**Parameters**:
161+
- `port` - Port number to check
162+
- `timeout` - Maximum time to wait in milliseconds (default: 30000)
163+
164+
**Throws**:
165+
- `ProcessReadyTimeoutError` - Port not available within timeout
166+
- `ProcessExitedBeforeReadyError` - Process exited before port became available
167+
168+
<TypeScriptExample>
169+
```
170+
const proc = await sandbox.startProcess('bun run server.js');
171+
172+
// Wait for port to accept connections
173+
await proc.waitForPort(8080);
174+
175+
// Now safe to make requests or expose the port
176+
const { url } = await sandbox.exposePort(8080, {
177+
hostname: request.url
178+
});
179+
```
180+
</TypeScriptExample>
181+
114182
### `listProcesses()`
115183

116184
List all running processes.

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

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,39 @@ 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 `waitForLog()` to wait for a specific log message:
89+
90+
<TypeScriptExample>
91+
```
92+
const server = await sandbox.startProcess('node server.js');
93+
94+
// Wait for readiness message
95+
await server.waitForLog('Server listening on port 3000');
96+
console.log('Server is ready!');
97+
98+
// Wait with regex and extract values
99+
const result = await server.waitForLog(/listening on port (\d+)/);
100+
console.log('Started on port:', result.match[1]);
101+
```
102+
</TypeScriptExample>
103+
104+
Or use `waitForPort()` to wait for a port to accept connections:
105+
106+
<TypeScriptExample>
107+
```
108+
const server = await sandbox.startProcess('bun run server.js');
109+
110+
// Wait for port to be ready
111+
await server.waitForPort(8080);
112+
console.log('Server is accepting connections on port 8080');
113+
```
114+
</TypeScriptExample>
115+
116+
### Monitor process logs
117+
118+
You can also stream logs in real-time for debugging:
89119

90120
<TypeScriptExample>
91121
```
@@ -137,24 +167,20 @@ Start services in sequence, waiting for dependencies:
137167

138168
<TypeScriptExample>
139169
```
140-
import { parseSSEStream, type LogEvent } from '@cloudflare/sandbox';
141-
142170
// Start database first
143171
const db = await sandbox.startProcess('redis-server');
144172
145173
// 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-
}
174+
await db.waitForLog('Ready to accept connections');
152175
153176
// Now start API server (depends on database)
154177
const api = await sandbox.startProcess('node api-server.js', {
155178
env: { DATABASE_URL: 'redis://localhost:6379' }
156179
});
157180
181+
// Wait for API to be ready
182+
await api.waitForPort(3000);
183+
158184
console.log('All services running');
159185
```
160186
</TypeScriptExample>
@@ -207,7 +233,7 @@ When using `keepAlive: true`, containers will not automatically timeout. You **m
207233

208234
## Best practices
209235

210-
- **Wait for readiness** - Stream logs to detect when services are ready
236+
- **Wait for readiness** - Use `waitForLog()` or `waitForPort()` to ensure services are ready before proceeding
211237
- **Clean up** - Always stop processes when done
212238
- **Handle failures** - Monitor logs for errors and restart if needed
213239
- **Use try/finally** - Ensure cleanup happens even on errors

src/content/docs/sandbox/guides/expose-services.mdx

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ export default {
4545
const sandbox = getSandbox(env.Sandbox, 'my-sandbox');
4646
4747
// 1. Start a web server
48-
await sandbox.startProcess('python -m http.server 8000');
48+
const proc = await sandbox.startProcess('python -m http.server 8000');
4949
50-
// 2. Wait for service to start
51-
await new Promise(resolve => setTimeout(resolve, 2000));
50+
// 2. Wait for port to be ready
51+
await proc.waitForPort(8000);
5252
5353
// 3. Expose the port
5454
const exposed = await sandbox.exposePort(8000, { hostname });
@@ -97,14 +97,14 @@ When exposing multiple ports, use names to stay organized:
9797
// Extract hostname from request
9898
const { hostname } = new URL(request.url);
9999
100-
// Start and expose API server
101-
await sandbox.startProcess('node api.js', { env: { PORT: '8080' } });
102-
await new Promise(resolve => setTimeout(resolve, 2000));
100+
// Start API and wait for readiness
101+
const apiProc = await sandbox.startProcess('node api.js', { env: { PORT: '8080' } });
102+
await apiProc.waitForPort(8080);
103103
const api = await sandbox.exposePort(8080, { hostname, name: 'api' });
104104
105-
// Start and expose frontend
106-
await sandbox.startProcess('npm run dev', { env: { PORT: '5173' } });
107-
await new Promise(resolve => setTimeout(resolve, 2000));
105+
// Start frontend and wait for readiness
106+
const frontendProc = await sandbox.startProcess('npm run dev', { env: { PORT: '5173' } });
107+
await frontendProc.waitForPort(5173);
108108
const frontend = await sandbox.exposePort(5173, { hostname, name: 'frontend' });
109109
110110
console.log('Services:');
@@ -115,42 +115,33 @@ console.log('- Frontend:', frontend.exposedAt);
115115

116116
## Wait for service readiness
117117

118-
Always verify a service is ready before exposing. Use a simple delay for most cases:
118+
Always verify a service is ready before exposing. Use `waitForPort()` to wait for the port to accept connections:
119119

120120
<TypeScriptExample>
121121
```
122122
// Extract hostname from request
123123
const { hostname } = new URL(request.url);
124124
125-
// Start service
126-
await sandbox.startProcess('npm run dev', { env: { PORT: '8080' } });
125+
// Start service and wait for port
126+
const proc = await sandbox.startProcess('npm run dev', { env: { PORT: '8080' } });
127+
await proc.waitForPort(8080);
127128
128-
// Wait 2-3 seconds
129-
await new Promise(resolve => setTimeout(resolve, 2000));
130-
131-
// Now expose
129+
// Now safe to expose
132130
await sandbox.exposePort(8080, { hostname });
133131
```
134132
</TypeScriptExample>
135133

136-
For critical services, poll the health endpoint:
134+
Or use `waitForLog()` to wait for a specific readiness message:
137135

138136
<TypeScriptExample>
139137
```
140138
// Extract hostname from request
141139
const { hostname } = new URL(request.url);
142140
143-
await sandbox.startProcess('node api-server.js', { env: { PORT: '8080' } });
144-
145-
// Wait for health check
146-
for (let i = 0; i < 10; i++) {
147-
await new Promise(resolve => setTimeout(resolve, 1000));
141+
const proc = await sandbox.startProcess('node api-server.js', { env: { PORT: '8080' } });
148142
149-
const check = await sandbox.exec('curl -f http://localhost:8080/health || echo "not ready"');
150-
if (check.stdout.includes('ok')) {
151-
break;
152-
}
153-
}
143+
// Wait for readiness log
144+
await proc.waitForLog('Server listening on port 8080');
154145
155146
await sandbox.exposePort(8080, { hostname });
156147
```
@@ -165,26 +156,26 @@ Expose multiple ports for full-stack applications:
165156
// Extract hostname from request
166157
const { hostname } = new URL(request.url);
167158
168-
// Start backend
169-
await sandbox.startProcess('node api/server.js', {
159+
// Start backend and wait for readiness
160+
const backend = await sandbox.startProcess('node api/server.js', {
170161
env: { PORT: '8080' }
171162
});
172-
await new Promise(resolve => setTimeout(resolve, 2000));
163+
await backend.waitForPort(8080);
173164
174-
// Start frontend
175-
await sandbox.startProcess('npm run dev', {
165+
// Start frontend and wait for readiness
166+
const frontend = await sandbox.startProcess('npm run dev', {
176167
cwd: '/workspace/frontend',
177168
env: { PORT: '5173', API_URL: 'http://localhost:8080' }
178169
});
179-
await new Promise(resolve => setTimeout(resolve, 3000));
170+
await frontend.waitForPort(5173);
180171
181172
// Expose both
182173
const api = await sandbox.exposePort(8080, { hostname, name: 'api' });
183-
const frontend = await sandbox.exposePort(5173, { hostname, name: 'frontend' });
174+
const frontendUrl = await sandbox.exposePort(5173, { hostname, name: 'frontend' });
184175
185176
return Response.json({
186177
api: api.exposedAt,
187-
frontend: frontend.exposedAt
178+
frontend: frontendUrl.exposedAt
188179
});
189180
```
190181
</TypeScriptExample>
@@ -224,7 +215,7 @@ for (const port of [3000, 5173, 8080]) {
224215

225216
## Best practices
226217

227-
- **Wait for readiness** - Don't expose ports immediately after starting processes
218+
- **Wait for readiness** - Use `waitForPort()` or `waitForLog()` before exposing ports
228219
- **Use named ports** - Easier to track when exposing multiple ports
229220
- **Clean up** - Unexpose ports when done to prevent abandoned URLs
230221
- **Add authentication** - Preview URLs are public; protect sensitive services

0 commit comments

Comments
 (0)