Skip to content

Conversation

@whoiskatrin
Copy link
Collaborator

@whoiskatrin whoiskatrin commented Dec 12, 2025

Implemented waitForExit(timeout?) method to Process objects

also replaced the arbitrary setTimeout(resolve, 3000) workaround with waitForExit():

  • Now uses the waitForExit() API to wait for the background process to complete
  • Validates exit code and verifies stdout output from the WaitForExitResult
  • More reliable and deterministic than arbitrary delays

fixes #297

@changeset-bot
Copy link

changeset-bot bot commented Dec 12, 2025

🦋 Changeset detected

Latest commit: 4df089d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@cloudflare/sandbox Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 12, 2025

Open in StackBlitz

npm i https://pkg.pr.new/cloudflare/sandbox-sdk/@cloudflare/sandbox@299

commit: 4df089d

@github-actions
Copy link
Contributor

github-actions bot commented Dec 12, 2025

🐳 Docker Images Published

Default:

FROM cloudflare/sandbox:0.0.0-pr-299-09e6d55

With Python:

FROM cloudflare/sandbox:0.0.0-pr-299-09e6d55-python

With OpenCode:

FROM cloudflare/sandbox:0.0.0-pr-299-09e6d55-opencode

Version: 0.0.0-pr-299-09e6d55

Use the -python variant if you need Python code execution, or -opencode for the variant with OpenCode AI coding agent pre-installed.


📦 Standalone Binary

For arbitrary Dockerfiles:

COPY --from=cloudflare/sandbox:0.0.0-pr-299-09e6d55 /container-server/sandbox /sandbox
ENTRYPOINT ["/sandbox"]

Download via GitHub CLI:

gh run download 20169928424 -n sandbox-binary

Extract from Docker:

docker run --rm cloudflare/sandbox:0.0.0-pr-299-09e6d55 cat /container-server/sandbox > sandbox && chmod +x sandbox

claude[bot]

This comment was marked as outdated.

claude[bot]

This comment was marked as outdated.

claude[bot]

This comment was marked as outdated.

{
method: 'POST',
headers,
body: JSON.stringify({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests call custom endpoint that doesn't exist in production container. Should use SDK directly:

// Instead of HTTP call to custom endpoint
const result = await startData.waitForExit(30000);

Current approach tests test worker implementation, not actual SDK.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still seeing the same pattern in the new tests. Lines 363-373 in process-readiness-workflow.test.ts use HTTP fetch calls to custom endpoints. The E2E tests should use the SDK directly to validate the actual API users will consume.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still relevant - custom endpoint added but no E2E tests using it. Added this to my main review.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The custom endpoint was added but no E2E tests were created that actually call the SDK. The test suite needs tests that verify process.waitForExit() works end-to-end in a real Worker environment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The custom endpoint was added but no E2E tests were created that actually call the SDK. The test suite needs tests that verify process.waitForExit() works end-to-end in a real Worker environment.

@whoiskatrin whoiskatrin marked this pull request as ready for review December 12, 2025 12:44
claude[bot]

This comment was marked as outdated.

Copy link
Member

@ghostwriternr ghostwriternr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall - but there's a lot of work being done to fetch logs, but I think we can separate concerns and keep waitForExit focused and leave fetching logs to the existing methods.

Comment on lines 119 to 122
/** Accumulated stdout output */
stdout: string;
/** Accumulated stderr output */
stderr: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the other waitFor methods, I think we can leave out accumulated logs from being returned in the response. If users need it, they anyway have access to the various log fetching utils right now. This method has a simple purpose that already gets solved without these.

Comment on lines 1544 to 1546
const existingLogs = await this.getProcessLogs(processId);
collectedStdout = existingLogs.stdout;
collectedStderr = existingLogs.stderr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we remove the logs from output, we can perhaps completely get rid of all log-related logic from here.

Comment on lines 1567 to 1568
// Stream logs and wait for exit event
const stream = await this.streamProcessLogs(processId);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

});
});

describe('waitForExit() method', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests can be more concise. Lots of overlap with current setup.

);
}, 60000);

test('should wait for process to exit and return exit code with output', async () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no-op: v nice e2e tests

@ghostwriternr
Copy link
Member

Minor import order merge conflicts too, sorry about that

Remove stdout/stderr accumulation from waitForExit() per review feedback.
Users can fetch logs separately via getProcessLogs() or streamProcessLogs()
if needed. This keeps the method focused on its single responsibility.
Copy link
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

The waitForExit() implementation is clean and follows established patterns. The exit code fallback logic is correct - I verified that 'killed' and 'error' statuses don't set exitCode in the container runtime.

Issues to address:

  1. Missing E2E tests - Custom test endpoint exists but no tests use it. Other readiness methods (waitForLog, waitForPort) have comprehensive E2E coverage in process-readiness-workflow.test.ts. This needs equivalent tests.

  2. Generic Error instead of typed error - Line 1559 throws plain Error for process not found. Should use ProcessNotFoundError for consistency with other process methods.

Minor improvements:

  1. Add clarifying comment at line 1556 explaining why status is checked every iteration (unlike waitForPort which checks every 3rd to reduce latency - here the status IS what we're waiting for).

  2. Consider enhancing JSDoc with @param, @returns, and @throws tags for consistency.

The unit tests are comprehensive and the implementation is architecturally sound. Just needs E2E coverage and the error type fix before merge.

const processInfo = await this.getProcess(processId);

if (!processInfo) {
throw new Error(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use ProcessNotFoundError instead of generic Error for consistency with other process methods.

if (!processInfo) {
  throw new ProcessNotFoundError({
    code: ErrorCode.PROCESS_NOT_FOUND,
    message: `Process ${processId} not found. It may have been cleaned up or never existed.`,
    context: { processId },
    httpStatus: 404,
    timestamp: new Date().toISOString()
  });
}

Streaming is more efficient - single request to container instead of
repeated polling. streamProcessLogs handles already-exited processes
gracefully by sending the exit event immediately.
agents-git-bot bot pushed a commit to cloudflare/cloudflare-docs that referenced this pull request Dec 12, 2025
Documents the new Process.waitForExit() method that allows waiting for
background processes to complete and retrieving their exit codes.

Related to cloudflare/sandbox-sdk#299
for await (const event of parseSSEStream<LogEvent>(stream)) {
if (event.type === 'exit') {
return {
exitCode: event.exitCode ?? 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: should the fallback be 0 or 1? Assuming failure when we don't have a clean exit code might be better no?

claude[bot]

This comment was marked as outdated.

Copy link
Member

@ghostwriternr ghostwriternr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lessgooo

@whoiskatrin whoiskatrin merged commit d3252dc into main Dec 12, 2025
17 checks passed
@whoiskatrin whoiskatrin deleted the add-wait-for-exit branch December 12, 2025 14:42
@github-actions github-actions bot mentioned this pull request Dec 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add waitForExit() method to Process objects

2 participants