Pause, resume and snapshots
Pause a sandbox to stop paying for it and resume it later where it stopped, or take a snapshot to start new sandboxes from. A paused sandbox keeps its memory and its disk, and costs nothing while it is paused.
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.
Pause without memory
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 })pause() takes one option.
| TypeScript | Python | Default | What it does |
|---|---|---|---|
keepMemory | keep_memory | true / True | Keep a full memory snapshot. false persists the filesystem only |
Take a snapshot
A snapshot is a persistent copy of a sandbox that you can start new sandboxes
from. createSnapshot() pauses the sandbox while it takes the copy, and the
sandbox is running again when the call returns. The call returns the
snapshot's ID together with its 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. snapshotId (snapshot_id) is the namespaced name with its tag,
for example your-team/my-snapshot:default. names holds the namespaced
names without the tag, for example your-team/my-snapshot, and is empty for a
snapshot you did not name. 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 name with its tag, or the template ID with its tag (for example
abc123:default) 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
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. In TypeScript, fork() needs @impello/sdk
0.3.2 or later.
import { Sandbox } from '@impello/sdk'
const sandbox = await Sandbox.create('base')
await sandbox.commands.run('echo warm > /home/user/cache')
const forks = await sandbox.fork({ count: 2, timeoutMs: 600_000 })
for (const fork of forks) {
if (fork instanceof Error) {
throw fork
}
const result = await fork.commands.run('cat /home/user/cache')
console.log(fork.sandboxId, result.stdout)
}count defaults to 1. The forked sandboxes get their own timeout —
timeoutMs in TypeScript, in milliseconds, and timeout in Python, in seconds
— defaulting to 5 minutes. A count below 1 raises InvalidArgumentError
(InvalidArgumentException in Python).
There is a static form for forking by ID: Sandbox.fork(sandboxId, { count: 2 })
in TypeScript, Sandbox.fork(sandbox_id, count=2) in Python.
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.