perf(sandbox): bake the repo and schema, let the sandbox start itself
Cloud workspace creation hung forever in production. This fixes the cause and removes the design that produced it.
What was wrong
create configured the sandbox from outside, at request time: clone the repo, run host-service once to create the schema, seed two rows with raw SQL, start host-service — inferring each step's completion by grepping a log file. Measured on the sandbox from the failed production attempt:
| step | actual work | what the code waited | waste |
|---|---|---|---|
| clone | — | full history, 282 MiB | ~40s |
| migrate | 1.5s | timeout 25 node host-service.js | 23.5s |
| start host-service | 1.5s | sleep 8 | 6.5s |
timeout 25 wrapped a server that never exits, so it burned all 25s every time. host-service is listening in 1546 ms — measured inside a sandbox.
The API's tRPC route is capped at maxDuration = 60, so production killed the function mid-bootstrap. The row stayed provisioning, the UI polled a state that would never change, and the sandbox leaked (teardown only runs when create throws; a killed function doesn't). It never showed up locally because next dev has no function timeout.
What it does now
The expensive parts moved to image build time:
- Repo baked in (
--filter=blob:none), so a workspace does a one-ref--depth 1fetch onto a warm object store. Verified: a fresh sandbox came up onmainat a commit newer than the baked one. host.dbships pre-migrated. SQLite leaves the schema in the WAL until something checkpoints it, and a signalled process doesn't — the first attempt shipped an empty 4 KiB file, so the build checkpoints explicitly and asserts the size.- host-service seeds its own rows from its environment (
runSandboxSelfSeed), through its own schema instead of raw SQL executed from the API. This also retires the "seeded rows are raw SQL against a schema it shares no types with" entry in the mismatches doc.
Provisioning is one create call plus one fire-and-forget process.exec. No log greps, no sleeps, nothing awaited.
Measured
| before | after | |
|---|---|---|
| our bootstrap work | ~78s | ~4s |
| create → serving, end to end | killed at 60s | ~5s |
Benchmarked outside this code path to place the cost correctly, two runs per image:
| image | run 0 | run 1 |
|---|---|---|
blaxel/base-image:latest | 0.3s | 0.2s |
sup-min | 9.4s | 0.3s |
superset-hostsvc (repo baked in) | 0.4s | 0.2s |
Sandbox creation is sub-second once the image is warm, and the baked repo costs nothing there. The only cold-start is a one-time image pull of ~10s paid by the first workspace after each image rebuild — per image version, not per sandbox.
Three platform constraints found by running it
All recorded in docs/cloud-sandbox-mismatches.md:
- The image's ENTRYPOINT belongs to Blaxel. The SDK appends
ENTRYPOINT ["/usr/local/bin/sandbox-api"]only when the image declares none, and that binary serves/process,/fsand the preview routes. Declaring our own to auto-start host-service left a sandbox that returned 502 to every exec — and you cannot debug a sandbox whose exec is the broken thing. - The platform injects
PORT, beating the image'sENV. host-service tried to bind 80 (reserved, with 443 and 8080) and exitedEADDRINUSE. - There is no HTTP
/health. Readiness is thehealth.checktRPC procedure; a probe on/health404s and looks exactly like a sandbox that never started.
Verification
Full suite 16/16 packages 0 fail, typecheck 38/38, lint clean. End-to-end exercised against a real sandbox through the preview URL with a token: health.check returns {"status":"ok"}, and the sandbox's own tables show the self-seed worked — workspaces = one type='main' row on the requested branch, projects = one row at /workspace.
The canonical superset-hostsvc image has been rebuilt with this definition, so it is live for the next workspace created.
Follow-ups this doesn't do
- Repos that can't be baked — anyone's but ours — still need a cold clone. A per-project snapshot or volume (Blaxel exposes
/volumesand per-sandbox/snapshots) is how that case gets the same warm start. createstill runs inside the request. It now fits comfortably, but provisioning belongs in a job.- The host-service version handshake remains the top open item: more of a sandbox's behaviour is now frozen at image build, which makes stranding worse, not better.
Summary by cubic
Bakes a blobless repo and a pre-migrated host.db into the sandbox image, then starts host-service via /app/start.sh so the sandbox self-seeds its project and workspace on boot. Replaces request-time bootstrap (clone + raw SQL seed + fixed sleeps) with one provision plus a fire-and-forget start; creation drops from ~78s to ~4s and avoids function timeouts.
packages/host-service: readsSUPERSET_SANDBOX_*and inserts project/workspace at startup (runSandboxSelfSeed).packages/trpc: deletebootstrapSandbox;provisionSandbox({ workspaceEnv })passes env and starts/app/start.shvia@blaxel/coreprocess.exec.- Image (
scripts/sandbox/image.ts): bake repo (blobless) andhost.db.template; addstart.shandgit-askpass.sh; noENTRYPOINT.start.shcopies DB to/data, exports a non-reservedPORT, fetches the branch against the baked origin or shallow‑clones when the repo differs; credentials flow throughGIT_ASKPASS. - Readiness remains the tRPC
health.check. AddsSANDBOX_HOST_DB_PATH. - Desktop: allow deleting sandbox workspaces; show a pending spinner on submit and disable the button during creation.
Rollout
- Rebuild and publish the
superset-hostsvcimage fromscripts/sandbox/image.ts, then setBLAXEL_SANDBOX_IMAGE. - Replace callers of
bootstrapSandboxwithprovisionSandbox({ workspaceEnv }). ProvideSUPERSET_SANDBOX_*,HOST_DB_PATH(useSANDBOX_HOST_DB_PATH), andHOST_MIGRATIONS_FOLDER. - Ensure the provider allows
process.execand egress for tokened fetches; do not set a custom imageENTRYPOINT.
Summary by CodeRabbit
-
New Features
- Cloud workspaces now initialize automatically with the supplied repository, branch, configuration, and workspace identity.
- Sandbox startup supports repository checkout, authentication, database preparation, and configurable ports.
- Workspace creation now shows an in-progress state and prevents duplicate submissions.
-
Bug Fixes
- Destroying sandbox workspaces no longer depends on host-service inspection.
- Sandbox setup now handles matching and alternate repository sources more reliably.
-
Documentation
- Added guidance on sandbox requirements, startup behavior, readiness checks, and known cloud workspace limitations.