Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/content/docs/sandbox/sdk/migrate/api-map.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ For the steps, refer to [Replace the Sandbox class](/sandbox/sdk/migrate/replace
| -------------------------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| `class X extends Sandbox`, `export { Sandbox }` | Removed | `class X extends DurableObject` | Construct the classes of the package from `container`. |
| `getSandbox(ns, id, options)` | Native | [`env.NS.getByName(id)`](/durable-objects/api/namespace/#getbyname) | Validate names yourself. |
| `normalizeId`, `setSandboxName()` | Removed | Lowercase names yourself | Needed only when names become hostnames. |
| `normalizeId`, `setSandboxName()` | Removed | Lowercase names yourself | If you passed `normalizeId: true`, lowercase each name to reach the same Durable Object. |
| `sleepAfter`, `setSleepAfter()` | Native | [`container.setInactivityTimeout(ms)`](/containers/api/durable-object-container/#setinactivitytimeout) | At most 6 hours. Call it after `start()`, and again in the constructor. |
| `keepAlive`, `setKeepAlive()` | Pattern | An [alarm](/durable-objects/api/alarms/) that sends the container a request while work remains | Refer to [Sandbox lifetime](/sandbox/concepts/lifetime/#activity-keeps-an-instance-running). |
| `renewActivityTimeout()` | Native | Any request to the Durable Object | The timeout counts from when the Durable Object becomes inactive. |
Expand All @@ -40,11 +40,11 @@ For the steps, refer to [Replace the Sandbox class](/sandbox/sdk/migrate/replace
| `labels`, `setLabels()` | Native | [`container.start({ image, enableInternet, labels })`](/containers/api/durable-object-container/#start) | |
| `configure()` | Removed | Options on each call | |
| `setEnvVars()`, class `envVars` | Native | `container.start({ env })` or `container.exec(argv, { env })` | `exec()` does not inherit `start()` variables, except `PATH`. |
| Class `entrypoint`, `enableInternet` | Native | `container.start({ entrypoint, enableInternet })` | `enableInternet` defaults to `false`. It defaulted to `true` in 0.12. |
| Class `entrypoint`, `enableInternet` | Native | `container.start({ image, entrypoint, enableInternet })` | Pass `enableInternet` on every call. It defaulted to `true` in 0.12. |
| Class `defaultPort`, `requiredPorts` | Native | [`container.getTcpPort(port)`](/containers/api/durable-object-container/#gettcpport) | |
| `start()` | Native | [`container.start({ image, enableInternet })`](/containers/api/durable-object-container/#start) | Does not wait for the container. |
| `startAndWaitForPorts()`, `waitForPort()` | Pattern | Retry `getTcpPort(port).fetch()` | [Preview a web application](/sandbox/previews/) shows a readiness check. |
| `stop()`, `destroy()` | Native | [`container.signal()`](/containers/api/durable-object-container/#signal), [`container.destroy()`](/containers/api/durable-object-container/#destroy) | |
| `stop()`, `destroy()` | Native | [`container.signal()`](/containers/api/durable-object-container/#signal), [`container.destroy()`](/containers/api/durable-object-container/#destroy) | 0.12 `destroy()` also deleted [tokens and tunnels](#ports-preview-urls-and-tunnels). |
| `getState()` | Native | [`container.running`](/containers/api/durable-object-container/#running), [`container.monitor()`](/containers/api/durable-object-container/#monitor) | |
| `getContainerPlacementId()` | Pattern | Read `CLOUDFLARE_PLACEMENT_ID` from `/proc/1/environ` with `container.exec()` | The main process of the container has the variable. Commands do not. |
| `onStart`, `onStop`, `onError`, `onActivityExpired` | Pattern | Your code around `start()` and `monitor()` | |
Expand Down
10 changes: 4 additions & 6 deletions src/content/docs/sandbox/sdk/migrate/background-processes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ This page replaces `startProcess()`, the `Process` methods, `listProcesses()`, `

<Steps>

1. Add the scripts and methods from [Run background processes](/sandbox/commands/run-background-processes/) to your class, including the alarm handler, and `follow()` and `waitForLog()` from [Follow a background process](/sandbox/commands/follow-a-background-process/).
1. From [Run background processes](/sandbox/commands/run-background-processes/), add the `ROOT`, `RUN`, `CURRENT`, and `STATUS` constants, the `Status` type, and the `run()` function to your class file. Add its `status()`, `logs()`, `stop()`, and `alarm()` methods to your class. Leave out its `INACTIVITY_TIMEOUT_MS` constant and its constructor, which your class file already has. From [Follow a background process](/sandbox/commands/follow-a-background-process/), add the `WAIT` constant and the `follow()` and `waitForLog()` methods.

A Durable Object has one alarm. If your class already has an `alarm()` handler, such as the one from [Move every sandbox in one deploy](/sandbox/sdk/migrate/plan-the-move/#move-every-sandbox-in-one-deploy), merge the process checks into it rather than adding a second.

2. Change `startProcess()` to start the container with `ensureRunning()`, and to run each process with the working directory and environment that 0.12 gave it:
2. Add `startProcess()`. Unlike the version in Run background processes, it starts the container with `ensureRunning()`, and runs each process with the working directory and environment that 0.12 gave it:

```ts title="src/index.ts" ins={5,19,20}
export class MySandbox extends DurableObject<Env> {
Expand Down Expand Up @@ -71,8 +71,6 @@ This page replaces `startProcess()`, the `Process` methods, `listProcesses()`, `

0.12 ran each process in `/workspace`, with the variables from `envVars`. `exec()` starts in `/`, even when the image sets `WORKDIR`. It does not inherit the variables that `start()` sets, except `PATH`.

3. Remove `INACTIVITY_TIMEOUT_MS` from the scripts that you added in step 1. Your class file already defines it, so the constructor and the alarm handler keep the inactivity timeout of your class.

</Steps>

On this page, `sandbox` is the stub that `getByName()` returns.
Expand All @@ -95,7 +93,7 @@ const started = await sandbox.startProcess("dev", [
]);
```

Each process needs an ID. Where 0.12 generated one, such as `proc_1790379992394_6snsuw`, use `crypto.randomUUID()`. The ID becomes a directory name, so use only characters that are safe in a path.
Each process needs an ID. Where 0.12 generated one, such as `proc_1790379992394_6snsuw`, use `crypto.randomUUID()`. The ID becomes a directory name, so reject an ID unless it matches `^[A-Za-z0-9_-]+$` before you pass it to any process method. An ID such as `../app` would otherwise reach a directory outside `ROOT`.

`startProcess()` returns `false` when a process already uses the ID. 0.12 replaced the record instead, and the first process kept running without one. An ended process keeps its directory, so `startProcess()` also returns `false` for its ID. To start that ID again, delete the directory first, as [Stop processes](#stop-processes) describes.

Expand Down Expand Up @@ -239,7 +237,7 @@ await sandbox.stop("dev");

`stop()` sends `SIGTERM` to the process group, which reaches the processes that the command started. 0.12 sent `SIGKILL` 5 seconds later to any process still running, and ignored the `signal` argument. To stop a process that ignores `SIGTERM`, change `TERM` to `KILL` in `stop()`.

Replace `killAllProcesses()` with a `stop()` call for each running process that `listProcesses()` returns. Remove `cleanupCompletedProcesses()` and the `autoCleanup` option, which did nothing in 0.12. To delete the directory of an ended process, run `rm -rf` on it.
Replace `killAllProcesses()` with a `stop()` call for each running process that `listProcesses()` returns. Remove `cleanupCompletedProcesses()` and the `autoCleanup` option, which did nothing in 0.12. To delete the directory of an ended process, check its ID against the same pattern, then run `rm -rf` on `${ROOT}/${id}`.

## Replace callbacks

Expand Down
2 changes: 1 addition & 1 deletion src/content/docs/sandbox/sdk/migrate/backups.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ products:

import { PackageManagers, Steps, WranglerConfig } from "~/components";

Replace 0.12 `createBackup()` and `restoreBackup()` with Durable Object methods of the same names, built on `DirectoryBackup`. Your Worker calls them with the same options, and backups keep the 0.12 time to live. `DirectoryBackup` saves the directory to the same `BACKUP_BUCKET` binding as a compressed archive, and restores it as ordinary files. 0.12 saved a SquashFS image and mounted it over the directory. Backups that 0.12 created convert to 1.0 backups the first time you restore them.
Replace 0.12 `createBackup()` and `restoreBackup()` with Durable Object methods of the same names, built on `DirectoryBackup`. Your Worker calls them with the same options, and backups keep the 0.12 time to live. `DirectoryBackup` saves the directory to the same `BACKUP_BUCKET` binding as a compressed archive, and restores it as ordinary files. 0.12 saved the directory as a SquashFS image, a compressed read-only filesystem, and mounted the image over the directory. Backups that 0.12 created convert to 1.0 backups the first time you restore them.

To save the whole filesystem instead of one directory, use a Container snapshot. For more information, refer to [Save and restore a sandbox with snapshots](/sandbox/files/save-and-restore-a-workspace/).

Expand Down
4 changes: 3 additions & 1 deletion src/content/docs/sandbox/sdk/migrate/bucket-mounts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ This page replaces `mountBucket()`, `unmountBucket()`, their options, and their
&& rm -rf /var/lib/apt/lists/*
```

FUSE lets a process provide a filesystem, and `s3fs` uses it to present the objects in a bucket as files. For what else `S3Mount` needs, refer to [Requirements](/sandbox/reference/s3-mounts/#requirements).

2. Export `S3Gateway` from the main module of your Worker:

```ts title="src/index.ts"
Expand Down Expand Up @@ -212,7 +214,7 @@ export class MySandbox extends DurableObject<Env> {

Remove the `mountData()` calls from the other methods. A path that you mount after `intercept()` does not work, so mount every path that the sandbox needs here. To mount a path later, open a new sandbox. A restarted Durable Object runs `startContainer()` again, and `mount()` reuses a mount that already matches.

Each mount uses one of the [64 intercept targets](/containers/api/durable-object-container/#interceptoutboundhttp) of the container, and `unmount()` does not free it. Move outbound rules uses two. Give each job its own sandbox name instead of mounting a new prefix for each job in one container.
Mounts and the rules from Move outbound rules share the intercept entries of the container, and `unmount()` does not free them. Refer to [Intercept limit](/containers/api/durable-object-container/#intercept-limit). Give each job its own sandbox name instead of mounting a new prefix for each job in one container.

## Replace localBucket

Expand Down
8 changes: 4 additions & 4 deletions src/content/docs/sandbox/sdk/migrate/changes-in-1-0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ In 0.x, the `Sandbox` class from the package starts the container, keeps it runn

</SandboxSdkVersions>

`this.ctx.container` does what the 0.x SDK server did. It runs commands, connects to ports, intercepts outbound requests, and saves snapshots. The package keeps only small helpers, such as the `Files` class.
`this.ctx.container` does what the 0.x SDK server did. It runs commands, connects to ports, routes outbound requests from the container to code in your Worker, and saves the root filesystem of a container as a snapshot that a later container can start from. The package keeps only small helpers, such as the `Files` class.

Decisions that depend on your application stay in your code: how long a sandbox runs, what it can reach, and what happens when a call fails. For example, a cancelled command may already have changed files, and only your application knows whether running it again is safe.

Expand All @@ -37,17 +37,17 @@ Some 0.x features have no equivalent. For each 0.x API and its replacement, refe

## Decisions your code makes

A container has no Internet access unless `start()` passes `enableInternet: true`. To allow one destination, your class registers an outbound handler for its hostname. The handler can add a credential that the container never sees. For more information, refer to [Sandbox security](/sandbox/concepts/security/).
A container has no Internet access unless `start()` passes `enableInternet: true`. To allow one destination, your class registers an outbound handler for its hostname. An outbound handler is Worker code that receives each request that the container sends to that hostname. The handler can add a credential that the container never sees. For more information, refer to [Sandbox security](/sandbox/concepts/security/).

`exec()` takes an array of arguments and starts that process without a shell. Text passed as an argument cannot start a second command. A shell runs only when you start one, such as `["sh", "-c", "npm ci && npm test"]`. Each call also sets its own `cwd` and `env`. No session carries them from one call to the next.

Your class decides how long a sandbox runs by setting the inactivity timeout after `start()`, and again in the constructor when a restarted Durable Object finds the container running. A deploy does not replace running containers. A new image applies only to containers that start after the deploy. The same holds for code that your class runs only when it starts a container, such as the calls that register outbound handlers. A handler that is already registered runs the code of the new version, with the props it was registered with. For more information, refer to [Sandbox lifetime](/sandbox/concepts/lifetime/).
Your class decides how long a sandbox runs, through the inactivity timeout that it sets on the container. A deploy does not replace running containers. A new image applies only to containers that start after the deploy. The same holds for code that your class runs only when it starts a container, such as the calls that register outbound handlers. A handler that is already registered runs the code of the new version, with the props it was registered with. For more information, refer to [Sandbox lifetime](/sandbox/concepts/lifetime/).

Your image provides every tool that your commands use. The 0.x image includes Python, Git, `curl`, `wget`, `jq`, `unzip`, and `ps`. `cloudflare/debian-trixie` and `node:24-trixie-slim`, which these pages use, include none of them. `Files`, `S3Mount`, and `DirectoryBackup` also need the `sandbox-shim` helper in the image. For the `COPY` line, refer to [`@cloudflare/sandbox` requirements](/sandbox/reference/#requirements).

The package writes nothing to Durable Object storage. A preview token, a process record, or a snapshot ID exists only if your class stores it. The keys that 0.x wrote stay in storage. The package ignores them, and your class can read them, as the pages that move preview URLs, tunnels, and outbound rules do.

The package also retries nothing and sets no time limits. To stop a command that runs too long, run it under GNU coreutils `timeout`, as [Replace timeouts](/sandbox/sdk/migrate/commands/#replace-timeouts) describes.
The package also retries nothing and sets no time limits. To limit how long a command runs, refer to [Replace timeouts](/sandbox/sdk/migrate/commands/#replace-timeouts).

## Related resources

Expand Down
4 changes: 2 additions & 2 deletions src/content/docs/sandbox/sdk/migrate/code-interpreter.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ If your code relies on this, or on contexts that you create, follow [Keep Python
| `runCode()` with `language: "javascript"` or `"typescript"` | [Run JavaScript in a Dynamic Worker](#run-javascript-in-a-dynamic-worker) |
| `runCodeStream()`, `onStdout`, `onStderr`, `onResult` | [Replace streaming output](#replace-streaming-output) |

Variables that 0.12 contexts held stay in the 0.12 container, and 0.12 context IDs are not in the storage of your Durable Object. After the switch, run your setup code again, and create your contexts again before the first `runCode()` call.

## Keep Python variables between calls

A kernel is a Python process that runs the code of each call with IPython, and keeps its variables until it exits. Your Durable Object starts one kernel for each context, on its own port.
Expand Down Expand Up @@ -473,8 +475,6 @@ A kernel is a Python process that runs the code of each call with IPython, and k

</Steps>

Variables that 0.12 contexts held stay in the 0.12 container. After the switch, run your setup code again, and create your contexts again, because 0.12 context IDs are not in the storage of your Durable Object.

## Run JavaScript in a Dynamic Worker

Run JavaScript in a [Dynamic Worker](/dynamic-workers/) that your Worker loads, so JavaScript needs no container.
Expand Down
Loading
Loading