Checkpoints, snapshots and forks
Save a running desktop's full state, start new desktops from it, or fork it into N copies at once.
Checkpoints
Every desktop is restored from a checkpoint: a saved process tree (memory, open files, the X session, the apps) plus its file system. There are two kinds:
- Base images, such as
osworld-ubuntu, installed on the host by the operator and named by a template version. They are never deleted by leases. - Saved states, which you make from a running desktop. In the console they are Snapshots; in the SDK a
State; in the HTTP API a checkpoint with a UUID id.
client.images() (GET /v1/checkpoints) lists both kinds that your workspace can launch on its host.
Save a state
env.save() (HTTP capture) saves the desktop's current state; the desktop keeps running. Start new desktops from it with client.create(from_state=state):
import drums
with drums.connect() as client:
with client.create(task="e0df059f", ttl=900) as env:
env.wait_valid()
env.step("pyautogui.click(960, 540)")
state = env.save(name="after-first-click") # a snapshot in the console
print("saved", state)
with client.create(from_state=state, ttl=600) as copy:
copy.wait_valid()
print("restored", copy.id, copy.from_state == state)
client.delete_state(state) # frees ~0.6 GB of host memorySaving is safe right after an action: the runtime first waits until the process tree is quiet (no process or thread starting or exiting for 1 s, at most 30 s by default) and checks that what it dumped is that tree. If the tree never becomes quiet, NotQuiescent is raised and nothing is captured.
Fork
env.fork(n) (HTTP branch) saves the desktop's state and starts n new desktops from it concurrently. Each child is an independent computer with its own id and a new episode with its own gate report; the parent keeps running.
import drums
with drums.connect() as client:
with client.create(task="e0df059f", ttl=900) as env:
env.wait_valid()
# closes the children when the block ends
with env.fork(2, keep_state=False) as kids:
print("fork state", kids.state, "children", [k.id for k in kids])
for k in kids:
k.wait_valid() # raises GateFailed if the child's episode is invalid
print(k.id, k.episode, k.gates()["validity"]["verdict"])keep_state=Falsedeletes the fork's saved state when its last child closes. Use it in loops: otherwise each fork keeps one saved state until you delete it or its lease runs out.strict=True(the default) raisesForkErrorif any child did not come up;ForkError.okholds the children that did.- Children count against your workspace's live-computer limit, and
nis limited by the host (max_fork_n, 8 on the current pilot host). See Limits. - A child inherits the parent's set-up task state; the task's setup is not run again.
Where saved states live
Important
Saved states live in the worker host's memory (a RAM-backed state directory). They are lost if the host reboots, restore only on the host that captured them, and cannot be downloaded. Each one holds about 0.6 GB of host memory, and the host holds a limited number (5 on the current pilot host).
| Lease | Default | Change it with |
|---|---|---|
| Idle timeout: deleted after this long with no desktop made from it | 1800 s | save(idle_timeout=), fork(state_idle_timeout=) |
| Time to live once no desktop uses it | none | save(ttl=), fork(state_ttl=) |
A saved state cannot be deleted while a desktop made from it exists (Conflict, HTTP 409). Base images cannot be deleted through the API.
In the console
Snapshots lists saved states with their lineage: the parent snapshot, the computer it was captured from, and the computers made from it. A ready snapshot can be restored into one new computer, forked, or deleted (by its creator, admins and owners). Snapshot states are Capturing, Ready, Failed, Deleting and Deleted.