Pause, resume and snapshots
A paused sandbox keeps its memory and its disk, costs nothing while it sits there, and resumes where it stopped.
Pause a sandbox
pause() stops the sandbox and writes its state to a snapshot. Memory is kept
by default, so running processes and open files survive.
import { Sandbox } from '@impello/sdk'
// Reads IMPELLO_API_KEY from the environment.
const sandbox = await Sandbox.create('base')
await sandbox.files.write('/home/user/state.json', '{"step": 1}')
const paused = await sandbox.pause()
console.log(paused) // trueThe call returns true when it paused the sandbox and false when the sandbox
was already paused, so pausing twice is safe. A sandbox that does not exist
raises SandboxNotFoundError (SandboxNotFoundException in Python); see
Errors.
Both SDKs also expose pause as a static call, so you can pause by ID without
holding an instance: Sandbox.pause(sandboxId) in TypeScript and
Sandbox.pause(sandbox_id) in Python.
Resume
Sandbox.connect(sandboxId) resumes a paused sandbox and hands back a client
for it. The sandbox must be running or paused; anything else raises
SandboxNotFoundError.
import { Sandbox } from '@impello/sdk'
const sandbox = await Sandbox.create('base')
const sandboxId = sandbox.sandboxId
await sandbox.pause()
// Later, in another process.
const resumed = await Sandbox.connect(sandboxId, { timeoutMs: 600_000 })
console.log(await resumed.files.read('/home/user/state.json'))
await resumed.kill()A resumed sandbox starts a fresh timeout: 5 minutes unless you pass one.
timeoutMs is milliseconds in TypeScript, timeout is seconds in Python. For
a running sandbox the timeout only moves if the new value is longer than the
one already set. See Timeouts.
An instance you already hold has the same method: await sandbox.connect() in
TypeScript, sandbox.connect() in Python. That is the shortest way back into a
sandbox you paused a moment ago.
Disk-only pause
Pass keepMemory: false (keep_memory=False in Python) to drop the in-memory
state and persist only the filesystem. Resuming such a sandbox cold-boots it
from disk: the files are there, the running processes and open connections are
not. A sandbox paused this way must be resumed explicitly with connect().
import { Sandbox } from '@impello/sdk'
const sandbox = await Sandbox.create('base')
await sandbox.pause({ keepMemory: false })| TypeScript | Python | Default | What it does |
|---|---|---|---|
keepMemory | keep_memory | true / True | Keep a full memory snapshot. false persists the filesystem only |
Snapshots
A snapshot is a persistent image of a sandbox that you can start new sandboxes
from. createSnapshot() pauses the sandbox while it takes the image;
Sandbox.connect(sandboxId) brings it back. The call returns the snapshot's ID
together with its full names.
import { Sandbox } from '@impello/sdk'
const sandbox = await Sandbox.create('base')
await sandbox.files.write('/home/user/state.json', '{"step": 1}')
const snapshot = await sandbox.createSnapshot({ name: 'my-snapshot' })
console.log(snapshot.snapshotId, snapshot.names)
// Start a fresh sandbox from it.
const fromSnapshot = await Sandbox.create(snapshot.snapshotId)
console.log(await fromSnapshot.files.read('/home/user/state.json'))
await fromSnapshot.kill()
// Kill the source sandbox if you are done with it.
await sandbox.kill()name is optional. Passing one that already exists adds a new build to that
snapshot instead of creating a second one, so a nightly job can keep writing to
the same name. names holds the namespaced, tag-qualified names of the
snapshot, for example your-team/my-snapshot:v2. The part before the slash is
your team namespace, not a project name.
Snapshots are persistent and survive the sandbox they came from: killing the source sandbox does not remove them, and they only go when you delete them.
Snapshots are not billed; see Limits and pricing. A deleted snapshot's data is removed within 30 days.
List snapshots
listSnapshots() returns a paginator. Called on an instance it lists only that
sandbox's snapshots; called on Sandbox it lists all of them.
import { Sandbox } from '@impello/sdk'
const paginator = Sandbox.listSnapshots({ limit: 50 })
while (paginator.hasNext) {
for (const snapshot of await paginator.nextItems()) {
console.log(snapshot.snapshotId, snapshot.names)
}
}The static form takes sandboxId (sandbox_id); both forms take limit and
nextToken (next_token). The Python SDK also takes name, which filters by
snapshot name or ID and accepts a tag — "my-snapshot",
"your-team/my-snapshot" or "my-snapshot:v1". The TypeScript SDK has no
name filter.
Delete a snapshot
Pass the snapshotId (snapshot_id) that createSnapshot handed you. It is a
namespaced, tag-qualified name, or the template ID with its tag (for example
:latest) when you did not pass a name.
import { Sandbox } from '@impello/sdk'
const sandbox = await Sandbox.create('base')
const snapshot = await sandbox.createSnapshot({ name: 'my-snapshot' })
const deleted = await Sandbox.deleteSnapshot(snapshot.snapshotId)
console.log(deleted) // false if there was no such snapshotFork a running sandbox
Forking is Python-only; the TypeScript SDK has no equivalent.
fork() checkpoints the sandbox in place: it is briefly paused, snapshotted
with its full memory state, and resumed, keeping its ID and its expiry. It then
starts count new sandboxes from that snapshot. The snapshot is captured once
however many forks you ask for.
from impello import Sandbox
sandbox = Sandbox.create("base")
sandbox.commands.run("echo warm > /home/user/cache")
fork1, fork2 = sandbox.fork(count=2, timeout=600)
for fork in (fork1, fork2):
if isinstance(fork, Exception):
raise fork
print(fork.sandbox_id, fork.commands.run("cat /home/user/cache").stdout)
count defaults to 1 and timeout is the forked sandboxes' own timeout in
seconds, defaulting to 300. A count below 1 raises
InvalidArgumentException.
There is a static form for forking by ID:
Sandbox.fork(sandbox_id, count=2).
How long a paused sandbox lives
A sandbox that has sat paused for 14 days is deleted along with its disk. The clock restarts every time you pause, so a sandbox you resume and pause again gets a fresh 14 days. Snapshots are not affected by this; they persist until you delete them.
Paused sandboxes are not billed. They hold their disk and cost nothing, and billing starts again when they resume.
A paused sandbox does not count against your concurrency limit, and there is no limit on how many sandboxes you keep paused. See Limits and pricing.
To see what you have paused, filter the sandbox list by state.
import { Sandbox } from '@impello/sdk'
const paginator = Sandbox.list({ query: { state: ['paused'] } })
while (paginator.hasNext) {
for (const s of await paginator.nextItems()) {
console.log(s.sandboxId, s.state)
}
}AsyncSandbox has the same methods with every network call awaited, including
fork() — except list() and list_snapshots(), which stay synchronous and
hand back an AsyncSandboxPaginator / AsyncSnapshotPaginator whose
next_items() you await.
Next: Metrics.