feat: run_background_job() on SandboxClient + AsyncSandboxClient#482
feat: run_background_job() on SandboxClient + AsyncSandboxClient#482
Conversation
Adds run_background_job() to both SandboxClient and AsyncSandboxClient.
Combines start_background_job() + polling into a single convenience
method for long-running commands that would exceed HTTP timeouts with
execute_command().
Usage:
result = await client.run_background_job(sandbox_id, command, timeout=900)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f75d45244a
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| for _elapsed in range(0, timeout + poll_interval, poll_interval): | ||
| status = await self.get_background_job(sandbox_id, job) | ||
| if status.completed: | ||
| return status | ||
| await _asyncio.sleep(poll_interval) |
There was a problem hiding this comment.
Enforce timeout ceiling in async polling loop
The async implementation can wait significantly longer than the requested timeout because range(0, timeout + poll_interval, poll_interval) schedules an extra poll window and each iteration unconditionally sleeps poll_interval after polling. In practice, timeout=10 and poll_interval=3 can block for about 15 seconds before raising TimeoutError, which contradicts the method contract that timeout is the maximum wait.
Useful? React with 👍 / 👎.
…ration counting The async version used range() to count loop iterations, which didn't account for time spent in API calls and could exceed the timeout. Now uses time.monotonic() deadline matching the sync implementation. Also removes redundant inline imports since time and asyncio are already imported at module level. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
…n_background_job The built-in TimeoutError is uncatchable by users importing TimeoutError from the package (which is aliased to APITimeoutError). Now raises CommandTimeoutError, consistent with every other command timeout in sandbox.py. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Summary
Adds
run_background_job()to bothSandboxClientandAsyncSandboxClient— a convenience method that combinesstart_background_job()+ polling into a single call.Problem
Long-running sandbox commands (e.g. running test suites for 10+ minutes) can't use
execute_command()because the HTTP connection times out. Users currently have to manually implementstart_background_job()+ pollget_background_job()in a loop. This pattern is duplicated across multiple TaskSpec implementations and validation code.Solution
API
Raises
TimeoutErrorif the command doesn't complete within the timeout.🤖 Generated with Claude Code
Note
Low Risk
Low risk additive change that introduces a new helper method; main concern is callers relying on default polling/timeout behavior for long-running commands.
Overview
Adds
run_background_job()to bothSandboxClientandAsyncSandboxClient, providing a single call that starts a background job, pollsget_background_job()until completion, and returns the finalBackgroundJobStatus.The helper supports
timeout,working_dir,env, andpoll_interval, and raisesCommandTimeoutErrorwhen the deadline is exceeded.Written by Cursor Bugbot for commit 4a73c7a. This will update automatically on new commits. Configure here.