diff --git a/docs/sandbox.mdx b/docs/sandbox.mdx index 6c37ccd3..301d4b74 100644 --- a/docs/sandbox.mdx +++ b/docs/sandbox.mdx @@ -134,3 +134,5 @@ sandbox = Sandbox.create(timeout=60) sandbox.kill() ``` + +For details on how the SDK handles operations during state transitions (pause, resume, kill) and a reference of possible errors, see [Behavior during state transitions](/docs/sandbox/persistence#behavior-during-state-transitions). diff --git a/docs/sandbox/auto-resume.mdx b/docs/sandbox/auto-resume.mdx index 06d04e33..a734bb92 100644 --- a/docs/sandbox/auto-resume.mdx +++ b/docs/sandbox/auto-resume.mdx @@ -66,6 +66,8 @@ That includes SDK operations like: If a sandbox is paused and `autoResume` is enabled, the next supported operation resumes it automatically. You do not need to call [`Sandbox.connect()`](/docs/sandbox/connect) first. +When auto-resume triggers, the SDK handles the resume transparently — if the sandbox is mid-transition, operations wait for the transition to complete. See [Behavior during state transitions](/docs/sandbox/persistence#behavior-during-state-transitions) for the full error reference. + ### SDK example: pause, then read a file diff --git a/docs/sandbox/connect.mdx b/docs/sandbox/connect.mdx index e62977e4..63baae49 100644 --- a/docs/sandbox/connect.mdx +++ b/docs/sandbox/connect.mdx @@ -74,3 +74,5 @@ r = sandbox.commands.run("whoami") print(f"Running in sandbox {sandbox.sandbox_id} as \"{r.stdout.strip()}\"") ``` + +If the sandbox is paused, `Sandbox.connect()` automatically resumes it before returning. If the sandbox is mid-transition (for example, currently pausing), the SDK waits for the transition to complete. See [Behavior during state transitions](/docs/sandbox/persistence#behavior-during-state-transitions) for details and error handling. diff --git a/docs/sandbox/persistence.mdx b/docs/sandbox/persistence.mdx index 3042df07..f5ab1634 100644 --- a/docs/sandbox/persistence.mdx +++ b/docs/sandbox/persistence.mdx @@ -69,6 +69,81 @@ sandbox.kill() # Running/Paused → Killed ``` +## Behavior during state transitions + +Lifecycle operations like `pause()`, `connect()`, and `kill()` can take a variable amount of time to complete — pausing, for example, takes approximately 4 seconds per GiB of RAM. If you call an SDK operation while a sandbox is mid-transition, the SDK automatically waits for the transition to finish and then executes your operation. From your code's perspective, the transition appears instant. + + +You do not need to poll sandbox state or add retry logic around transitions. The SDK handles waiting for you. + + +Here's what happens in specific scenarios: + +| Scenario | What the SDK does | +|---|---| +| Call `commands.run()` while sandbox is pausing | Waits for pause to complete, then resumes the sandbox, then runs the command | +| Call `connect()` on a paused sandbox | Automatically resumes the sandbox and returns a connected instance | +| Call `connect()` on an already-running sandbox | Connects immediately — no state change needed | +| Call `kill()` from any state | Transitions the sandbox to Killed, regardless of current state | +| Call `pause()` on an already-paused sandbox | Returns immediately — no-op | + +### Errors during lifecycle operations + +When a lifecycle operation fails, the SDK raises one of the following errors. This table covers the most common cases — see the full error reference for [JavaScript](/docs/sdk-reference/js-sdk/v2.14.1/errors) and [Python](/docs/sdk-reference/python-sdk/v2.9.1/exceptions). + +| Operation | Error (JS / Python) | When it occurs | +|---|---|---| +| `pause()` | `NotFoundError` / `NotFoundException` | Sandbox doesn't exist or was already killed | +| `connect()` | `NotFoundError` / `NotFoundException` | Sandbox ID doesn't exist | +| `connect()` | `TimeoutError` / `TimeoutException` | Resume didn't complete within the timeout window | +| `kill()` | `NotFoundError` / `NotFoundException` | Sandbox doesn't exist | +| Any operation during a transition | `TimeoutError` / `TimeoutException` | The transition plus the operation together exceeded the request timeout | + +Here's an example of handling errors during lifecycle operations: + + +```js JavaScript & TypeScript +import { Sandbox, TimeoutError, NotFoundError } from '@e2b/code-interpreter' + +const sbx = await Sandbox.create() +const sandboxId = sbx.sandboxId + +await sbx.pause() + +try { + // connect() automatically resumes a paused sandbox + const resumed = await Sandbox.connect(sandboxId) + const result = await resumed.commands.run('echo hello') + console.log(result.stdout) +} catch (error) { + if (error instanceof NotFoundError) { + console.error('Sandbox no longer exists:', error.message) + } else if (error instanceof TimeoutError) { + console.error('Operation timed out during transition:', error.message) + } +} +``` +```python Python +from e2b_code_interpreter import Sandbox +from e2b import TimeoutException, NotFoundException + +sbx = Sandbox.create() +sandbox_id = sbx.sandbox_id + +sbx.pause() + +try: + # connect() automatically resumes a paused sandbox + resumed = Sandbox.connect(sandbox_id) + result = resumed.commands.run("echo hello") + print(result.stdout) +except NotFoundException as e: + print(f"Sandbox no longer exists: {e}") +except TimeoutException as e: + print(f"Operation timed out during transition: {e}") +``` + + ## Pausing sandbox When you pause a sandbox, both the sandbox's filesystem and memory state will be saved. This includes all the files in the sandbox's filesystem and all the running processes, loaded variables, data, etc.