Pre-warmed Session Pool
Pre-create sandbox sessions so that POST /v1/sessions can return in sub-100ms when a session is available in the pool (target ~50ms), instead of ~200–450ms for a cold create.
How It Works
Daemon Startup
├─ Create N sandboxes per configured image (no workspace)
├─ Store sessions with status "pool_idle" (not subject to TTL expiry)
└─ Pool ready
User Creates Session (with or without workspace_id)
├─ pool.Get(image) → session available? → acquire from pool (~50–80ms) ✅
├─ If workspace_id: nsenter bind-mount workspace into /workspace
├─ Update status to "running", set TTL, return to user
├─ Refill pool in background (replenish 1 session)
└─ If pool empty → normal create (~200–450ms), then refill in background
Scope: The pool supports both sessions with and without workspace_id. Pooled sessions start without a workspace; when a request includes workspace_id, the workspace directory is bind-mounted into /workspace at acquire time via nsenter.
Configuration
pool:
enabled: true
images:
python: 3 # keep 3 Python sessions ready
node: 2 # keep 2 Node sessions ready
enabled(default:false): Turn pooling on. Keep disabled if you don’t need sub-100ms create latency.images: Map of image name → number of pre-warmed sessions to maintain.
Pool images are filtered by allowed_images. If allowed_images is set and an image is not in the list, it is not pooled.
Environment override: SANDKASTEN_POOL_ENABLED=true
When to Use
Pooling helps when:
- Session creation is a hot path (many sessions per second)
- Sub-100ms latency is important
- You want to hide cold-start overhead
For typical usage (~100–200ms cold create), pooling is optional.
Implementation Details
- Pool lifecycle: At daemon startup,
RefillAllcreates the configured number of sandboxes per image. They are stored with statuspool_idleand a far-future expiry so the reaper does not destroy them. - Acquire:
pool.Getreturns a session ID, which is removed from the pool. The session status is updated torunningandexpires_atis set to the user’s TTL. - Refill: After each create (pool hit or normal), a background goroutine calls
Refillto add one session back for that image. - Release: When a session is destroyed, it is not returned to the pool. The pool is replenished on demand by
Refillafter future creates.
Workspace Support
Sessions created with workspace_id can also use the pool. The flow:
- Take an idle session from the pool (created without workspace)
- Use
nsenterto enter the sandbox’s mount namespace - Bind-mount the workspace directory into
/workspace - Update the store and return the session to the user
Adds ~10–30ms to pool acquire for the bind-mount step, still much faster than cold create. Requires workspace.enabled: true and the workspace to exist (created via ensureWorkspace before acquire).